[Pkg-javascript-commits] [sax.js] 01/15: Imported Upstream version 0.5.5

Jérémy Lal kapouer at alioth.debian.org
Mon Sep 23 00:23:25 UTC 2013


This is an automated email from the git hooks/post-receive script.

kapouer pushed a commit to branch master
in repository sax.js.

commit ca152a199ae45949d9be8c1e1f760e5d95764954
Author: Jérémy Lal <kapouer at melix.org>
Date:   Mon Sep 23 02:05:53 2013 +0200

    Imported Upstream version 0.5.5
---
 AUTHORS                                    |    1 +
 LICENSE                                    |   47 +--
 LICENSE-W3C.html                           |  188 ++++++++++++
 README.md                                  |    3 +-
 component.json                             |   12 +
 examples/example.js                        |   50 ++--
 examples/switch-bench.js                   |   45 ---
 lib/sax.js                                 |  436 ++++++++++++++++++++++++----
 package.json                               |   20 +-
 test/attribute-name.js                     |   33 +++
 test/buffer-overrun.js                     |    3 +-
 test/case.js                               |    9 +-
 test/cdata-chunked.js                      |    2 +-
 test/cdata-end-split.js                    |    2 +-
 test/cdata-fake-end.js                     |    4 +-
 test/cdata-multiple.js                     |    2 +-
 test/cdata.js                              |    2 +-
 test/cyrillic.js                           |    8 +
 test/duplicate-attribute.js                |   13 +
 test/entities.js                           |   10 +
 test/entity-mega.js                        |   16 +
 test/issue-23.js                           |   16 +-
 test/issue-30.js                           |    4 +-
 test/issue-35.js                           |    2 +-
 test/issue-47.js                           |    9 +-
 test/issue-49.js                           |    8 +-
 test/issue-84.js                           |   13 +
 test/script-close-better.js                |   12 +
 test/script.js                             |    6 +-
 test/self-closing-child-strict.js          |   12 +-
 test/self-closing-child.js                 |   12 +-
 test/self-closing-tag.js                   |    8 +-
 test/stray-ending.js                       |    4 +-
 test/trailing-attribute-no-value.js        |   10 +
 test/trailing-non-whitespace.js            |    3 +-
 test/unclosed-root.js                      |   11 +
 test/unquoted.js                           |    3 +-
 test/utf8-split.js                         |   32 ++
 test/xmlns-issue-41.js                     |    1 +
 test/xmlns-rebinding.js                    |   12 +-
 test/xmlns-strict.js                       |   19 +-
 test/xmlns-unbound-element.js              |   33 +++
 test/xmlns-unbound.js                      |    2 +-
 test/xmlns-xml-default-ns.js               |   31 ++
 test/xmlns-xml-default-prefix-attribute.js |    1 +
 test/xmlns-xml-default-prefix.js           |    1 +
 test/xmlns-xml-default-redefine.js         |    1 +
 47 files changed, 948 insertions(+), 224 deletions(-)

diff --git a/AUTHORS b/AUTHORS
index 26d8659..7145cbc 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -7,3 +7,4 @@ Jann Horn <jann at Jann-PC.fritz.box>
 Elijah Insua <tmpvar at gmail.com>
 Henry Rawas <henryr at schakra.com>
 Justin Makeig <jmpublic at makeig.com>
+Mike Schilling <mike at emotive.com>
diff --git a/LICENSE b/LICENSE
index 05a4010..62e4ccf 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,23 +1,32 @@
-Copyright 2009, 2010, 2011 Isaac Z. Schlueter.
+Copyright (c) Isaac Z. Schlueter ("Author")
 All rights reserved.
 
-Permission is hereby granted, free of charge, to any person
-obtaining a copy of this software and associated documentation
-files (the "Software"), to deal in the Software without
-restriction, including without limitation the rights to use,
-copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following
-conditions:
+The BSD License
 
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
 
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+The file "examples/strict.dtd" is licensed by the W3C and used according
+to the terms of the W3C SOFTWARE NOTICE AND LICENSE.  See LICENSE-W3C.html
+for details.
diff --git a/LICENSE-W3C.html b/LICENSE-W3C.html
new file mode 100644
index 0000000..a611e3f
--- /dev/null
+++ b/LICENSE-W3C.html
@@ -0,0 +1,188 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><meta name="generator" content="HTML Tidy for Mac OS X (vers 31 October 2006 - Apple Inc. build 13), see www.w3.org" /><title>W3C Software Notice and License</title><link rel="stylesheet" href="/2008/site/css/minimum" type="text/css" media="handheld, all" /><style type="text/css" media="print, screen and (min-width: 481px)" xml:space="preserve">
+     @import url("/2008/site/css/advanced");
+</style><link href="/2008/site/css/minimum" rel="stylesheet" type="text/css" media="handheld, only screen and (max-device-width: 480px)" /><meta name="viewport" content="width=device-width" /><link rel="stylesheet" href="/2008/site/css/print" type="text/css" media="print" /><link rel="shortcut icon" href="/2008/site/images/favicon.ico" type="image/x-icon" /></head><body id="www-w3-org" class="w3c_public"><div id="w3c_container">
+    
+    
+
+         <div id="w3c_mast">
+            <h1 class="logo">
+               <a tabindex="2" accesskey="1" href="/"><img src="/2008/site/images/logo-w3c-mobile-lg" width="90" height="53" alt="W3C" /></a>
+               <span class="alt-logo">W3C</span>
+            </h1>
+
+            <div id="w3c_nav">
+               
+               
+
+               <form action="/Help/search" method="get" enctype="application/x-www-form-urlencoded"><div class="w3c_sec_nav"><!-- --></div><ul class="main_nav"><li class="first-item">
+                        <a href="/standards/">Standards</a>
+                     </li><li>
+                        <a href="/participate/">Participate</a>
+                     </li><li>
+                        <a href="/Consortium/membership">Membership</a>
+                     </li><li class="last-item">
+                        <a href="/Consortium/">About W3C</a>
+                     </li><li class="search-item">
+                        <div id="search-form">
+                           <input tabindex="3" class="text" name="q" value="" title="Search" type="text" />
+                           <button id="search-submit" name="search-submit" type="submit"><img class="submit" src="/2008/site/images/search-button" alt="Search" width="21" height="17" /></button>
+                        </div>
+                     </li></ul></form>
+            </div>
+            
+         </div>
+         
+
+         <div id="w3c_main">
+            <div id="w3c_logo_shadow" class="w3c_leftCol">
+               <img height="32" alt="" src="/2008/site/images/logo-shadow" />
+            </div>
+            
+            <div class="w3c_leftCol"><h2 class="offscreen">Site Navigation</h2>
+    <h3 class="category"><span class="ribbon"><a href="/Consortium/Legal/ipr-notice.html" title="Up to Policies and Legal Information">Policies and Legal Information <img src="/2008/site/images/header-link" alt="Header link" width="13" height="13" class="header-link" /></a></span></h3>
+       <ul class="theme">
+        <li><a href="/Consortium/Legal/2008/04-testsuite-copyright.html">Licenses for W3C Test Suites</a></li>
+        <li><a href="/2004/10/27-testcases.html">Policies for Contribution of Test Cases to W3C</a></li>
+        <li><a href="/Consortium/Legal/IPR-FAQ-20000620.html">Intellectual Rights FAQ</a></li>
+        <li><a href="/Consortium/Legal/privacy-statement-20000612.html">W3C Privacy Statements</a></li>
+        <li><a href="/Consortium/Legal/2002/copyright-documents-20021231.html">W3C Document License</a></li>
+        <li><a href="/Consortium/Legal/2002/trademarks-20021231.html">W3C Trademarks and Generic Terms</a></li>
+        <li><a href="/Consortium/Legal/2002/trademark-license-20021231.html">W3C&#xAE; Trademark and Service Mark License</a></li>
+        <li><a class="current">W3C Software Notice and License</a></li>
+        <li><a href="/Consortium/Legal/2002/collaborators-agreement-20021231.html">W3C Invited Expert and Collaborators Agreement</a></li>
+        <li><a href="/Consortium/Persistence.html">W3C URI Persistence Policy</a></li>
+        <li><a href="/1999/10/21-mirroring-policy.html">Mirroring the W3C Site</a></li>
+        <li><a href="/Consortium/Legal/2006/08-copyright-translations.html">Translations of the Copyright Notice</a></li>
+       </ul>
+       <br /></div>
+            <div class="w3c_mainCol">
+               <div id="w3c_crumbs">
+       <div id="w3c_crumbs_frame">
+        <ul class="bct"> <!-- .bct / Breadcrumbs -->
+          <li class="skip"><a tabindex="1" accesskey="2" title="Skip to content (e.g., when browsing via audio)" href="#w3c_content_body">Skip</a></li>
+          <li><a href="/">W3C</a>&#xA0;<span class="cr">&#xBB;</span>&#xA0;</li>
+          <li><a href="/Consortium/">About&#xA0;W3C</a>&#xA0;<span class="cr">&#xBB;</span>&#xA0;</li>
+          <li><a href="/Consortium/facts.html">Facts&#xA0;About&#xA0;W3C</a>&#xA0;<span class="cr">&#xBB;</span>&#xA0;</li>
+          <li><a href="/Consortium/Legal/ipr-notice.html">Policies&#xA0;and&#xA0;Legal&#xA0;Information</a>&#xA0;<span class="cr">&#xBB;</span>&#xA0;</li>
+          <li class="current">W3C Software Notice and License</li>
+        </ul>            
+     </div>
+    </div>
+               <h1 class="title">W3C Software Notice and License</h1>
+               <div id="w3c_content_body">
+                  <div class="line">
+                     <p class="intro tPadding">This work (and included software, documentation such as READMEs, or other
+related items) is being provided by the copyright holders under the following
+license.</p>
+<h2>License</h2>
+                     
+                     <p class="tPadding">
+By obtaining, using and/or copying this work, you (the licensee)
+agree that you have read, understood, and will comply with the following
+terms and conditions.</p>
+
+                     <p>Permission to copy, modify, and distribute this software and its
+documentation, with or without modification,&#xA0;for any purpose and without
+fee or royalty is hereby granted, provided that you include the following on
+ALL copies of the software and documentation or portions thereof, including
+modifications:</p>
+
+                     <ul class="show_items"><li>The full text of this NOTICE in a location viewable to users of the
+    redistributed or derivative work.</li><li>Any pre-existing intellectual property disclaimers, notices, or terms
+    and conditions. If none exist, the <a href="copyright-software-short-notice-20021231.html">W3C Software Short
+    Notice</a> should be included (hypertext is preferred, text is permitted)
+    within the body of any redistributed or derivative code.</li><li>Notice of any changes or modifications to the files, including the date
+    changes were made. (We recommend you provide URIs to the location from
+    which the code is derived.)</li></ul>
+
+<h2>Disclaimers</h2>
+
+                     <p>THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS
+MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
+PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE
+ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.</p>
+
+                     <p>COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR
+DOCUMENTATION.</p>
+
+                     <p>The name and trademarks of copyright holders may NOT be used in
+advertising or publicity pertaining to the software without specific, written
+prior permission. Title to copyright in this software and any associated
+documentation will at all times remain with copyright holders.</p>
+
+                     <h2>Notes</h2>
+
+	                    <p>This version: http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231</p>
+
+                     <p>This formulation of W3C's notice and license became active on December 31
+2002. This version removes the copyright ownership notice such that this
+license can be used with materials other than those owned by the W3C,
+reflects that ERCIM is now a host of the W3C, includes references to this
+specific dated version of the license, and removes the ambiguous grant of
+"use". Otherwise, this version is the same as the <a href="http://www.w3.org/Consortium/Legal/copyright-software-19980720">previous
+version</a> and is written so as to preserve the <a href="http://www.gnu.org/philosophy/license-list.html#GPLCompatibleLicenses">Free
+Software Foundation's assessment of GPL compatibility</a> and <a href="http://www.opensource.org/licenses/W3C.php">OSI's certification</a>
+under the <a href="http://www.opensource.org/docs/definition.php">Open Source
+Definition</a>.</p>
+                  </div>
+               </div>
+            </div>
+         </div>
+         
+         
+         
+      </div><div id="w3c_footer">
+         <div id="w3c_footer-inner">
+            <h2 class="offscreen">Footer Navigation</h2>
+            <div class="w3c_footer-nav">
+               <h3>Navigation</h3>
+               <ul class="footer_top_nav"><li>
+                     <a href="/">Home</a>
+                  </li><li>
+                     <a href="/standards/">Standards</a>
+                  </li><li>
+                     <a href="/participate/">Participate</a>
+                  </li><li>
+                     <a href="/Consortium/membership">Membership</a>
+                  </li><li class="last-item">
+                     <a href="/Consortium/">About W3C</a>
+                  </li></ul>
+            </div>
+            <div class="w3c_footer-nav">
+               <h3>Contact W3C</h3>
+               <ul class="footer_bottom_nav"><li>
+                     <a href="/Consortium/contact">Contact</a>
+                  </li><li>
+                     <a accesskey="0" href="/Help/">Help and FAQ</a>
+                  </li><li>
+                     <a href="/Consortium/sponsor/">Sponsor / Donate</a>
+                  </li><li>
+                     <a href="/Consortium/siteindex">Site Map</a>
+                  </li><li>
+                     <address id="w3c_signature">
+                        <a href="http://lists.w3.org/Archives/Public/site-comments/">Feedback</a></address>
+                  </li></ul>
+            </div>
+            <div class="w3c_footer-nav">
+               <h3>W3C Updates</h3>
+               <ul class="footer_follow_nav"><li>
+                     <a href="http://twitter.com/W3C" title="Follow W3C on Twitter">
+                        <img src="/2008/site/images/twitter-bird" alt="Twitter" width="78" height="83" class="social-icon" />
+                     </a>
+                     <a href="http://identi.ca/w3c" title="See W3C on Identica">
+                        <img src="/2008/site/images/identica-logo" alt="Identica" width="91" height="83" class="social-icon" />
+                     </a>
+                  </li></ul>
+            </div>
+            <p class="copyright">Copyright &#xA9; 2012 W3C <sup>&#xAE;</sup> (<a href="http://www.csail.mit.edu/">
+                  <acronym title="Massachusetts Institute of Technology">MIT</acronym>
+               </a>, <a href="http://www.ercim.org/">
+                  <acronym title="European Research Consortium for Informatics and Mathematics"> ERCIM</acronym>
+               </a>, <a href="http://www.keio.ac.jp/">Keio</a>) <a href="/Consortium/Legal/ipr-notice">Usage policies apply</a>.</p>
+         </div>
+      </div><!-- Generated from data/scripts.php, ../../smarty/{scripts.tpl} --><!-- At the bottom for performance reasons --><div id="w3c_scripts">
+         <script type="text/javascript" src="/2008/site/js/main" xml:space="preserve"><!-- --></script>
+      </div></body></html>
diff --git a/README.md b/README.md
index 2e5462b..c965242 100644
--- a/README.md
+++ b/README.md
@@ -81,7 +81,7 @@ through unmolested.
     // same chunks coming in also go out.
     fs.createReadStream("file.xml")
       .pipe(saxStream)
-      .pipe(fs.createReadStream("file-copy.xml"))
+      .pipe(fs.createWriteStream("file-copy.xml"))
 
 
 
@@ -101,6 +101,7 @@ Settings supported:
 * `lowercase` - Boolean. If true, then lowercase tag names and attribute names
   in loose mode, rather than uppercasing them.
 * `xmlns` - Boolean. If true, then namespaces are supported.
+* `position` - Boolean. If false, then don't track line/col/position.
 
 ## Methods
 
diff --git a/component.json b/component.json
new file mode 100644
index 0000000..96b5d73
--- /dev/null
+++ b/component.json
@@ -0,0 +1,12 @@
+{
+  "name": "sax",
+  "description": "An evented streaming XML parser in JavaScript",
+  "author": "Isaac Z. Schlueter <i at izs.me> (http://blog.izs.me/)",
+  "version": "0.5.2",
+  "main": "lib/sax.js",
+  "license": "BSD",
+  "scripts": [
+    "lib/sax.js"
+  ],
+  "repository": "git://github.com/isaacs/sax-js.git"
+}
diff --git a/examples/example.js b/examples/example.js
index e7f81e6..7b0246e 100644
--- a/examples/example.js
+++ b/examples/example.js
@@ -1,41 +1,29 @@
 
 var fs = require("fs"),
-  sys = require("sys"),
+  util = require("util"),
   path = require("path"),
-  xml = fs.cat(path.join(__dirname, "test.xml")),
+  xml = fs.readFileSync(path.join(__dirname, "test.xml"), "utf8"),
   sax = require("../lib/sax"),
   strict = sax.parser(true),
   loose = sax.parser(false, {trim:true}),
   inspector = function (ev) { return function (data) {
-    // sys.error("");
-    // sys.error(ev+": "+sys.inspect(data));
-    // for (var i in data) sys.error(i+ " "+sys.inspect(data[i]));
-    // sys.error(this.line+":"+this.column);
+    console.error("%s %s %j", this.line+":"+this.column, ev, data);
   }};
 
-xml.addCallback(function (xml) {
-  // strict.write(xml);
-  
-  sax.EVENTS.forEach(function (ev) {
-    loose["on"+ev] = inspector(ev);
-  });
-  loose.onend = function () {
-    // sys.error("end");
-    // sys.error(sys.inspect(loose));
-  };
-  
-  // do this one char at a time to verify that it works.
-  // (function () {
-  //   if (xml) {
-  //     loose.write(xml.substr(0,1000));
-  //     xml = xml.substr(1000);
-  //     process.nextTick(arguments.callee);
-  //   } else loose.close();
-  // })();
-  
-  for (var i = 0; i < 1000; i ++) {
-    loose.write(xml);
-    loose.close();
-  }
-
+sax.EVENTS.forEach(function (ev) {
+  loose["on"+ev] = inspector(ev);
 });
+loose.onend = function () {
+  console.error("end");
+  console.error(loose);
+};
+
+// do this in random bits at a time to verify that it works.
+(function () {
+  if (xml) {
+    var c = Math.ceil(Math.random() * 1000)
+    loose.write(xml.substr(0,c));
+    xml = xml.substr(c);
+    process.nextTick(arguments.callee);
+  } else loose.close();
+})();
diff --git a/examples/switch-bench.js b/examples/switch-bench.js
deleted file mode 100755
index 4d3cf14..0000000
--- a/examples/switch-bench.js
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/local/bin/node-bench
-
-var Promise = require("events").Promise;
-
-var xml = require("posix").cat("test.xml").wait(),
-  path = require("path"),
-  sax = require("../lib/sax"),
-  saxT = require("../lib/sax-trampoline"),
-  
-  parser = sax.parser(false, {trim:true}),
-  parserT = saxT.parser(false, {trim:true}),
-  
-  sys = require("sys");
-
-
-var count = exports.stepsPerLap = 500,
-  l = xml.length,
-  runs = 0;
-exports.countPerLap = 1000;
-exports.compare = {
-  "switch" : function () {
-    // sys.debug("switch runs: "+runs++);
-    // for (var x = 0; x < l; x += 1000) {
-    //   parser.write(xml.substr(x, 1000))
-    // }
-    // for (var i = 0; i < count; i ++) {
-      parser.write(xml);
-      parser.close();
-    // }
-    // done();
-  },
-  trampoline : function () {
-    // sys.debug("trampoline runs: "+runs++);
-    // for (var x = 0; x < l; x += 1000) {
-    //   parserT.write(xml.substr(x, 1000))
-    // }
-    // for (var i = 0; i < count; i ++) {
-      parserT.write(xml);
-      parserT.close();
-    // }
-    // done();
-  },
-};
-
-sys.debug("rock and roll...");
\ No newline at end of file
diff --git a/lib/sax.js b/lib/sax.js
index e44abc1..77e20ae 100644
--- a/lib/sax.js
+++ b/lib/sax.js
@@ -51,7 +51,7 @@ function SAXParser (strict, opt) {
   parser.q = parser.c = ""
   parser.bufferCheckPosition = sax.MAX_BUFFER_LENGTH
   parser.opt = opt || {}
-  parser.opt.lowercase = parser.opt.lowercase || parser.opt.lowercasetags;
+  parser.opt.lowercase = parser.opt.lowercase || parser.opt.lowercasetags
   parser.looseCase = parser.opt.lowercase ? "toLowerCase" : "toUpperCase"
   parser.tags = []
   parser.closed = parser.closedRoot = parser.sawRoot = false
@@ -68,7 +68,10 @@ function SAXParser (strict, opt) {
   if (parser.opt.xmlns) parser.ns = Object.create(rootNS)
 
   // mostly just for error reporting
-  parser.position = parser.line = parser.column = 0
+  parser.trackPosition = parser.opt.position !== false
+  if (parser.trackPosition) {
+    parser.position = parser.line = parser.column = 0
+  }
   emit(parser, "onready")
 }
 
@@ -155,7 +158,7 @@ function createStream (strict, opt) {
 function SAXStream (strict, opt) {
   if (!(this instanceof SAXStream)) return new SAXStream(strict, opt)
 
-  Stream.apply(me)
+  Stream.apply(this)
 
   this._parser = new SAXParser(strict, opt)
   this.writable = true
@@ -176,6 +179,8 @@ function SAXStream (strict, opt) {
     me._parser.error = null
   }
 
+  this._decoder = null;
+
   streamWraps.forEach(function (ev) {
     Object.defineProperty(me, "on" + ev, {
       get: function () { return me._parser["on" + ev] },
@@ -196,13 +201,24 @@ SAXStream.prototype = Object.create(Stream.prototype,
   { constructor: { value: SAXStream } })
 
 SAXStream.prototype.write = function (data) {
+  if (typeof Buffer === 'function' &&
+      typeof Buffer.isBuffer === 'function' &&
+      Buffer.isBuffer(data)) {
+    if (!this._decoder) {
+      var SD = require('string_decoder').StringDecoder
+      this._decoder = new SD('utf8')
+    }
+    data = this._decoder.write(data);
+  }
+
   this._parser.write(data.toString())
   this.emit("data", data)
   return true
 }
 
 SAXStream.prototype.end = function (chunk) {
-  if (chunk && chunk.length) this._parser.write(chunk.toString())
+  if (chunk && chunk.length) this.write(chunk)
+  else if (this.leftovers) this._parser.write(this.leftovers.toString())
   this._parser.end()
   return true
 }
@@ -230,8 +246,6 @@ var whitespace = "\r\n\t "
   , number = "0124356789"
   , letter = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
   // (Letter | "_" | ":")
-  , nameStart = letter+"_:"
-  , nameBody = nameStart+number+"-."
   , quote = "'\""
   , entity = number+letter+"#"
   , attribEnd = whitespace + ">"
@@ -245,8 +259,17 @@ var whitespace = "\r\n\t "
 whitespace = charClass(whitespace)
 number = charClass(number)
 letter = charClass(letter)
-nameStart = charClass(nameStart)
-nameBody = charClass(nameBody)
+
+// http://www.w3.org/TR/REC-xml/#NT-NameStartChar
+// This implementation works on strings, a single character at a time
+// as such, it cannot ever support astral-plane characters (10000-EFFFF)
+// without a significant breaking change to either this  parser, or the
+// JavaScript language.  Implementation of an emoji-capable xml parser
+// is left as an exercise for the reader.
+var nameStart = /[:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/
+
+var nameBody = /[:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u00B7\u0300-\u036F\u203F-\u2040\.\d-]/
+
 quote = charClass(quote)
 entity = charClass(entity)
 attribEnd = charClass(attribEnd)
@@ -258,12 +281,16 @@ function charClass (str) {
   }, {})
 }
 
+function isRegExp (c) {
+  return Object.prototype.toString.call(c) === '[object RegExp]'
+}
+
 function is (charclass, c) {
-  return charclass[c]
+  return isRegExp(charclass) ? !!c.match(charclass) : charclass[c]
 }
 
 function not (charclass, c) {
-  return !charclass[c]
+  return !is(charclass, c)
 }
 
 var S = 0
@@ -287,7 +314,6 @@ sax.STATE =
 , CDATA_ENDING_2            : S++ // ]]
 , PROC_INST                 : S++ // <?hi
 , PROC_INST_BODY            : S++ // <?hi there
-, PROC_INST_QUOTED          : S++ // <?hi "there
 , PROC_INST_ENDING          : S++ // <?hi "there" ?
 , OPEN_TAG                  : S++ // <strong
 , OPEN_TAG_SLASH            : S++ // <strong /
@@ -306,13 +332,267 @@ sax.STATE =
 }
 
 sax.ENTITIES =
-{ "apos" : "'"
+{ "amp" : "&"
+, "gt" : ">"
+, "lt" : "<"
 , "quot" : "\""
-, "amp"  : "&"
-, "gt"   : ">"
-, "lt"   : "<"
+, "apos" : "'"
+, "AElig" : 198
+, "Aacute" : 193
+, "Acirc" : 194
+, "Agrave" : 192
+, "Aring" : 197
+, "Atilde" : 195
+, "Auml" : 196
+, "Ccedil" : 199
+, "ETH" : 208
+, "Eacute" : 201
+, "Ecirc" : 202
+, "Egrave" : 200
+, "Euml" : 203
+, "Iacute" : 205
+, "Icirc" : 206
+, "Igrave" : 204
+, "Iuml" : 207
+, "Ntilde" : 209
+, "Oacute" : 211
+, "Ocirc" : 212
+, "Ograve" : 210
+, "Oslash" : 216
+, "Otilde" : 213
+, "Ouml" : 214
+, "THORN" : 222
+, "Uacute" : 218
+, "Ucirc" : 219
+, "Ugrave" : 217
+, "Uuml" : 220
+, "Yacute" : 221
+, "aacute" : 225
+, "acirc" : 226
+, "aelig" : 230
+, "agrave" : 224
+, "aring" : 229
+, "atilde" : 227
+, "auml" : 228
+, "ccedil" : 231
+, "eacute" : 233
+, "ecirc" : 234
+, "egrave" : 232
+, "eth" : 240
+, "euml" : 235
+, "iacute" : 237
+, "icirc" : 238
+, "igrave" : 236
+, "iuml" : 239
+, "ntilde" : 241
+, "oacute" : 243
+, "ocirc" : 244
+, "ograve" : 242
+, "oslash" : 248
+, "otilde" : 245
+, "ouml" : 246
+, "szlig" : 223
+, "thorn" : 254
+, "uacute" : 250
+, "ucirc" : 251
+, "ugrave" : 249
+, "uuml" : 252
+, "yacute" : 253
+, "yuml" : 255
+, "copy" : 169
+, "reg" : 174
+, "nbsp" : 160
+, "iexcl" : 161
+, "cent" : 162
+, "pound" : 163
+, "curren" : 164
+, "yen" : 165
+, "brvbar" : 166
+, "sect" : 167
+, "uml" : 168
+, "ordf" : 170
+, "laquo" : 171
+, "not" : 172
+, "shy" : 173
+, "macr" : 175
+, "deg" : 176
+, "plusmn" : 177
+, "sup1" : 185
+, "sup2" : 178
+, "sup3" : 179
+, "acute" : 180
+, "micro" : 181
+, "para" : 182
+, "middot" : 183
+, "cedil" : 184
+, "ordm" : 186
+, "raquo" : 187
+, "frac14" : 188
+, "frac12" : 189
+, "frac34" : 190
+, "iquest" : 191
+, "times" : 215
+, "divide" : 247
+, "OElig" : 338
+, "oelig" : 339
+, "Scaron" : 352
+, "scaron" : 353
+, "Yuml" : 376
+, "fnof" : 402
+, "circ" : 710
+, "tilde" : 732
+, "Alpha" : 913
+, "Beta" : 914
+, "Gamma" : 915
+, "Delta" : 916
+, "Epsilon" : 917
+, "Zeta" : 918
+, "Eta" : 919
+, "Theta" : 920
+, "Iota" : 921
+, "Kappa" : 922
+, "Lambda" : 923
+, "Mu" : 924
+, "Nu" : 925
+, "Xi" : 926
+, "Omicron" : 927
+, "Pi" : 928
+, "Rho" : 929
+, "Sigma" : 931
+, "Tau" : 932
+, "Upsilon" : 933
+, "Phi" : 934
+, "Chi" : 935
+, "Psi" : 936
+, "Omega" : 937
+, "alpha" : 945
+, "beta" : 946
+, "gamma" : 947
+, "delta" : 948
+, "epsilon" : 949
+, "zeta" : 950
+, "eta" : 951
+, "theta" : 952
+, "iota" : 953
+, "kappa" : 954
+, "lambda" : 955
+, "mu" : 956
+, "nu" : 957
+, "xi" : 958
+, "omicron" : 959
+, "pi" : 960
+, "rho" : 961
+, "sigmaf" : 962
+, "sigma" : 963
+, "tau" : 964
+, "upsilon" : 965
+, "phi" : 966
+, "chi" : 967
+, "psi" : 968
+, "omega" : 969
+, "thetasym" : 977
+, "upsih" : 978
+, "piv" : 982
+, "ensp" : 8194
+, "emsp" : 8195
+, "thinsp" : 8201
+, "zwnj" : 8204
+, "zwj" : 8205
+, "lrm" : 8206
+, "rlm" : 8207
+, "ndash" : 8211
+, "mdash" : 8212
+, "lsquo" : 8216
+, "rsquo" : 8217
+, "sbquo" : 8218
+, "ldquo" : 8220
+, "rdquo" : 8221
+, "bdquo" : 8222
+, "dagger" : 8224
+, "Dagger" : 8225
+, "bull" : 8226
+, "hellip" : 8230
+, "permil" : 8240
+, "prime" : 8242
+, "Prime" : 8243
+, "lsaquo" : 8249
+, "rsaquo" : 8250
+, "oline" : 8254
+, "frasl" : 8260
+, "euro" : 8364
+, "image" : 8465
+, "weierp" : 8472
+, "real" : 8476
+, "trade" : 8482
+, "alefsym" : 8501
+, "larr" : 8592
+, "uarr" : 8593
+, "rarr" : 8594
+, "darr" : 8595
+, "harr" : 8596
+, "crarr" : 8629
+, "lArr" : 8656
+, "uArr" : 8657
+, "rArr" : 8658
+, "dArr" : 8659
+, "hArr" : 8660
+, "forall" : 8704
+, "part" : 8706
+, "exist" : 8707
+, "empty" : 8709
+, "nabla" : 8711
+, "isin" : 8712
+, "notin" : 8713
+, "ni" : 8715
+, "prod" : 8719
+, "sum" : 8721
+, "minus" : 8722
+, "lowast" : 8727
+, "radic" : 8730
+, "prop" : 8733
+, "infin" : 8734
+, "ang" : 8736
+, "and" : 8743
+, "or" : 8744
+, "cap" : 8745
+, "cup" : 8746
+, "int" : 8747
+, "there4" : 8756
+, "sim" : 8764
+, "cong" : 8773
+, "asymp" : 8776
+, "ne" : 8800
+, "equiv" : 8801
+, "le" : 8804
+, "ge" : 8805
+, "sub" : 8834
+, "sup" : 8835
+, "nsub" : 8836
+, "sube" : 8838
+, "supe" : 8839
+, "oplus" : 8853
+, "otimes" : 8855
+, "perp" : 8869
+, "sdot" : 8901
+, "lceil" : 8968
+, "rceil" : 8969
+, "lfloor" : 8970
+, "rfloor" : 8971
+, "lang" : 9001
+, "rang" : 9002
+, "loz" : 9674
+, "spades" : 9824
+, "clubs" : 9827
+, "hearts" : 9829
+, "diams" : 9830
 }
 
+Object.keys(sax.ENTITIES).forEach(function (key) {
+    var e = sax.ENTITIES[key]
+    var s = typeof e === 'number' ? String.fromCharCode(e) : e
+    sax.ENTITIES[key] = s
+})
+
 for (var S in sax.STATE) sax.STATE[sax.STATE[S]] = S
 
 // shorthand
@@ -341,9 +621,11 @@ function textopts (opt, text) {
 
 function error (parser, er) {
   closeText(parser)
-  er += "\nLine: "+parser.line+
-        "\nColumn: "+parser.column+
-        "\nChar: "+parser.c
+  if (parser.trackPosition) {
+    er += "\nLine: "+parser.line+
+          "\nColumn: "+parser.column+
+          "\nChar: "+parser.c
+  }
   er = new Error(er)
   parser.error = er
   emit(parser, "onerror", er)
@@ -351,6 +633,7 @@ function error (parser, er) {
 }
 
 function end (parser) {
+  if (!parser.closedRoot) strictFail(parser, "Unclosed root tag")
   if (parser.state !== S.TEXT) error(parser, "Unexpected end")
   closeText(parser)
   parser.c = ""
@@ -361,6 +644,8 @@ function end (parser) {
 }
 
 function strictFail (parser, message) {
+  if (typeof parser !== 'object' || !(parser instanceof SAXParser))
+    throw new Error('bad call to strictFail');
   if (parser.strict) error(parser, message)
 }
 
@@ -391,6 +676,12 @@ function qname (name) {
 
 function attrib (parser) {
   if (!parser.strict) parser.attribName = parser.attribName[parser.looseCase]()
+
+  if (parser.attribList.indexOf(parser.attribName) !== -1 ||
+      parser.tag.attributes.hasOwnProperty(parser.attribName)) {
+    return parser.attribName = parser.attribValue = ""
+  }
+
   if (parser.opt.xmlns) {
     var qn = qname(parser.attribName)
       , prefix = qn.prefix
@@ -441,11 +732,12 @@ function openTag (parser, selfClosing) {
     var qn = qname(parser.tagName)
     tag.prefix = qn.prefix
     tag.local = qn.local
-    tag.uri = tag.ns[qn.prefix] || qn.prefix
+    tag.uri = tag.ns[qn.prefix] || ""
 
     if (tag.prefix && !tag.uri) {
       strictFail(parser, "Unbound namespace prefix: "
                        + JSON.stringify(parser.tagName))
+      tag.uri = qn.prefix
     }
 
     var parent = parser.tags[parser.tags.length - 1] || parser
@@ -458,6 +750,8 @@ function openTag (parser, selfClosing) {
     }
 
     // handle deferred onattribute events
+    // Note: do not apply default ns to attributes:
+    //   http://www.w3.org/TR/REC-xml-names/#defaulting
     for (var i = 0, l = parser.attribList.length; i < l; i ++) {
       var nv = parser.attribList[i]
       var name = nv[0]
@@ -465,7 +759,7 @@ function openTag (parser, selfClosing) {
         , qualName = qname(name)
         , prefix = qualName.prefix
         , local = qualName.local
-        , uri = tag.ns[prefix] || ""
+        , uri = prefix == "" ? "" : (tag.ns[prefix] || "")
         , a = { name: name
               , value: value
               , prefix: prefix
@@ -486,6 +780,8 @@ function openTag (parser, selfClosing) {
     parser.attribList.length = 0
   }
 
+  parser.tag.isSelfClosing = !!selfClosing
+
   // process the tag
   parser.sawRoot = true
   parser.tags.push(parser.tag)
@@ -511,6 +807,18 @@ function closeTag (parser) {
     parser.state = S.TEXT
     return
   }
+
+  if (parser.script) {
+    if (parser.tagName !== "script") {
+      parser.script += "</" + parser.tagName + ">"
+      parser.tagName = ""
+      parser.state = S.SCRIPT
+      return
+    }
+    emitNode(parser, "onscript", parser.script)
+    parser.script = ""
+  }
+
   // first make sure that the closing tag actually exists.
   // <a><b></c></b></a> will close everything, otherwise.
   var t = parser.tags.length
@@ -558,10 +866,15 @@ function closeTag (parser) {
 }
 
 function parseEntity (parser) {
-  var entity = parser.entity.toLowerCase()
+  var entity = parser.entity
+    , entityLC = entity.toLowerCase()
     , num
     , numStr = ""
-  if (parser.ENTITIES[entity]) return parser.ENTITIES[entity]
+  if (parser.ENTITIES[entity])
+    return parser.ENTITIES[entity]
+  if (parser.ENTITIES[entityLC])
+    return parser.ENTITIES[entityLC]
+  entity = entityLC
   if (entity.charAt(0) === "#") {
     if (entity.charAt(1) === "x") {
       entity = entity.slice(2)
@@ -589,16 +902,20 @@ function write (chunk) {
   if (chunk === null) return end(parser)
   var i = 0, c = ""
   while (parser.c = c = chunk.charAt(i++)) {
-    parser.position ++
-    if (c === "\n") {
-      parser.line ++
-      parser.column = 0
-    } else parser.column ++
+    if (parser.trackPosition) {
+      parser.position ++
+      if (c === "\n") {
+        parser.line ++
+        parser.column = 0
+      } else parser.column ++
+    }
     switch (parser.state) {
 
       case S.BEGIN:
-        if (c === "<") parser.state = S.OPEN_WAKA
-        else if (not(whitespace,c)) {
+        if (c === "<") {
+          parser.state = S.OPEN_WAKA
+          parser.startTagPosition = parser.position
+        } else if (not(whitespace,c)) {
           // have to process this as a text node.
           // weird, but happens.
           strictFail(parser, "Non-whitespace before first tag.")
@@ -612,7 +929,7 @@ function write (chunk) {
           var starti = i-1
           while (c && c!=="<" && c!=="&") {
             c = chunk.charAt(i++)
-            if (c) {
+            if (c && parser.trackPosition) {
               parser.position ++
               if (c === "\n") {
                 parser.line ++
@@ -622,10 +939,12 @@ function write (chunk) {
           }
           parser.textNode += chunk.substring(starti, i-1)
         }
-        if (c === "<") parser.state = S.OPEN_WAKA
-        else {
+        if (c === "<") {
+          parser.state = S.OPEN_WAKA
+          parser.startTagPosition = parser.position
+        } else {
           if (not(whitespace, c) && (!parser.sawRoot || parser.closedRoot))
-            strictFail("Text data outside of root node.")
+            strictFail(parser, "Text data outside of root node.")
           if (c === "&") parser.state = S.TEXT_ENTITY
           else parser.textNode += c
         }
@@ -640,10 +959,7 @@ function write (chunk) {
 
       case S.SCRIPT_ENDING:
         if (c === "/") {
-          emitNode(parser, "onscript", parser.script)
           parser.state = S.CLOSE_TAG
-          parser.script = ""
-          parser.tagName = ""
         } else {
           parser.script += "<" + c
           parser.state = S.SCRIPT
@@ -658,11 +974,9 @@ function write (chunk) {
         } else if (is(whitespace, c)) {
           // wait for it...
         } else if (is(nameStart,c)) {
-          parser.startTagPosition = parser.position - 1
           parser.state = S.OPEN_TAG
           parser.tagName = c
         } else if (c === "/") {
-          parser.startTagPosition = parser.position - 1
           parser.state = S.CLOSE_TAG
           parser.tagName = ""
         } else if (c === "?") {
@@ -670,6 +984,11 @@ function write (chunk) {
           parser.procInstName = parser.procInstBody = ""
         } else {
           strictFail(parser, "Unencoded <")
+          // if there was some whitespace, then add that in.
+          if (parser.startTagPosition + 1 < parser.position) {
+            var pad = parser.position - parser.startTagPosition
+            c = new Array(pad).join(" ") + c
+          }
           parser.textNode += "<" + c
           parser.state = S.TEXT
         }
@@ -812,11 +1131,7 @@ function write (chunk) {
       case S.PROC_INST_BODY:
         if (!parser.procInstBody && is(whitespace, c)) continue
         else if (c === "?") parser.state = S.PROC_INST_ENDING
-        else if (is(quote, c)) {
-          parser.state = S.PROC_INST_QUOTED
-          parser.q = c
-          parser.procInstBody += c
-        } else parser.procInstBody += c
+        else parser.procInstBody += c
       continue
 
       case S.PROC_INST_ENDING:
@@ -833,14 +1148,6 @@ function write (chunk) {
         }
       continue
 
-      case S.PROC_INST_QUOTED:
-        parser.procInstBody += c
-        if (c === parser.q) {
-          parser.state = S.PROC_INST_BODY
-          parser.q = ""
-        }
-      continue
-
       case S.OPEN_TAG:
         if (is(nameBody, c)) parser.tagName += c
         else {
@@ -879,6 +1186,12 @@ function write (chunk) {
 
       case S.ATTRIB_NAME:
         if (c === "=") parser.state = S.ATTRIB_VALUE
+        else if (c === ">") {
+          strictFail(parser, "Attribute without value")
+          parser.attribValue = parser.attribName
+          attrib(parser)
+          openTag(parser)
+        }
         else if (is(whitespace, c)) parser.state = S.ATTRIB_NAME_SAW_WHITE
         else if (is(nameBody, c)) parser.attribName += c
         else strictFail(parser, "Invalid attribute name")
@@ -942,13 +1255,22 @@ function write (chunk) {
       case S.CLOSE_TAG:
         if (!parser.tagName) {
           if (is(whitespace, c)) continue
-          else if (not(nameStart, c)) strictFail(parser,
-            "Invalid tagname in closing tag.")
-          else parser.tagName = c
+          else if (not(nameStart, c)) {
+            if (parser.script) {
+              parser.script += "</" + c
+              parser.state = S.SCRIPT
+            } else {
+              strictFail(parser, "Invalid tagname in closing tag.")
+            }
+          } else parser.tagName = c
         }
         else if (c === ">") closeTag(parser)
         else if (is(nameBody, c)) parser.tagName += c
-        else {
+        else if (parser.script) {
+          parser.script += "</" + parser.tagName
+          parser.tagName = ""
+          parser.state = S.SCRIPT
+        } else {
           if (not(whitespace, c)) strictFail(parser,
             "Invalid tagname in closing tag")
           parser.state = S.CLOSE_TAG_SAW_WHITE
@@ -958,7 +1280,7 @@ function write (chunk) {
       case S.CLOSE_TAG_SAW_WHITE:
         if (is(whitespace, c)) continue
         if (c === ">") closeTag(parser)
-        else strictFail("Invalid characters in closing tag")
+        else strictFail(parser, "Invalid characters in closing tag")
       continue
 
       case S.TEXT_ENTITY:
@@ -984,7 +1306,7 @@ function write (chunk) {
         }
         else if (is(entity, c)) parser.entity += c
         else {
-          strictFail("Invalid character entity")
+          strictFail(parser, "Invalid character entity")
           parser[buffer] += "&" + parser.entity + c
           parser.entity = ""
           parser.state = returnState
diff --git a/package.json b/package.json
index 9281cb0..8ee1759 100644
--- a/package.json
+++ b/package.json
@@ -1,10 +1,12 @@
-{ "name" : "sax"
-, "description": "An evented streaming XML parser in JavaScript"
-, "author" : "Isaac Z. Schlueter <i at izs.me> (http://blog.izs.me/)"
-, "version" : "0.4.0"
-, "main" : "lib/sax.js"
-, "license" : { "type": "MIT"
-              , "url": "https://raw.github.com/isaacs/sax-js/master/LICENSE" }
-, "scripts" : { "test" : "node test/index.js" }
-, "repository": "git://github.com/isaacs/sax-js.git"
+{
+  "name": "sax",
+  "description": "An evented streaming XML parser in JavaScript",
+  "author": "Isaac Z. Schlueter <i at izs.me> (http://blog.izs.me/)",
+  "version": "0.5.5",
+  "main": "lib/sax.js",
+  "license": "BSD",
+  "scripts": {
+    "test": "node test/index.js"
+  },
+  "repository": "git://github.com/isaacs/sax-js.git"
 }
diff --git a/test/attribute-name.js b/test/attribute-name.js
new file mode 100644
index 0000000..9ebbe58
--- /dev/null
+++ b/test/attribute-name.js
@@ -0,0 +1,33 @@
+require(__dirname).test(
+  { xml: "<root length='12345'></root>"
+  , expect: [
+    ["attribute", {
+      name: "length"
+    , value: "12345"
+    , prefix: ""
+    , local: "length"
+    , uri: ""
+    }]
+  , ["opentag", {
+      name: "root"
+    , prefix: ""
+    , local: "root"
+    , uri: ""
+    , attributes: {
+      length: {
+        name: "length"
+      , value: "12345"
+      , prefix: ""
+      , local: "length"
+      , uri: ""
+      }
+    }
+    , ns: {}
+    , isSelfClosing: false
+    }]
+  , ["closetag", "root"]
+  ]
+  , strict: true
+  , opt: { xmlns: true }
+  }
+)
diff --git a/test/buffer-overrun.js b/test/buffer-overrun.js
index 8d12fac..57d3c41 100644
--- a/test/buffer-overrun.js
+++ b/test/buffer-overrun.js
@@ -10,7 +10,8 @@ require(__dirname).test({
     ["error", "Max buffer length exceeded: tagName\nLine: 0\nColumn: 45\nChar: "],
     ["opentag", {
      "name": "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ",
-     "attributes": {}
+     "attributes": {},
+     "isSelfClosing": false
     }],
     ["text", "yo"],
     ["closetag", "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"]
diff --git a/test/case.js b/test/case.js
index 35ee934..9da78ab 100644
--- a/test/case.js
+++ b/test/case.js
@@ -6,7 +6,8 @@ require(__dirname).test
       [ [ "attribute", { name: "CLASS", value: "test" } ]
       , [ "attribute", { name: "HELLO", value: "world" } ]
       , [ "opentag", { name: "SPAN",
-                       attributes: { CLASS: "test", HELLO: "world" } } ]
+                       attributes: { CLASS: "test", HELLO: "world" },
+                       isSelfClosing: false } ]
       , [ "closetag", "SPAN" ]
       ]
     , strict : false
@@ -22,7 +23,8 @@ require(__dirname).test
       [ [ "attribute", { name: "class", value: "test" } ]
       , [ "attribute", { name: "hello", value: "world" } ]
       , [ "opentag", { name: "span",
-                       attributes: { class: "test", hello: "world" } } ]
+                       attributes: { class: "test", hello: "world" },
+                       isSelfClosing: false } ]
       , [ "closetag", "span" ]
       ]
     , strict : false
@@ -38,7 +40,8 @@ require(__dirname).test
       [ [ "attribute", { name: "class", value: "test" } ]
       , [ "attribute", { name: "hello", value: "world" } ]
       , [ "opentag", { name: "span",
-                       attributes: { class: "test", hello: "world" } } ]
+                       attributes: { class: "test", hello: "world" },
+                       isSelfClosing: false } ]
       , [ "closetag", "span" ]
       ]
     , strict : false
diff --git a/test/cdata-chunked.js b/test/cdata-chunked.js
index ccd5ee6..e3362bc 100644
--- a/test/cdata-chunked.js
+++ b/test/cdata-chunked.js
@@ -1,7 +1,7 @@
 
 require(__dirname).test({
   expect : [
-    ["opentag", {"name": "R","attributes": {}}],
+    ["opentag", {"name": "R","attributes": {}, "isSelfClosing": false}],
     ["opencdata", undefined],
     ["cdata", " this is character data  "],
     ["closecdata", undefined],
diff --git a/test/cdata-end-split.js b/test/cdata-end-split.js
index b41bd00..34f3450 100644
--- a/test/cdata-end-split.js
+++ b/test/cdata-end-split.js
@@ -1,7 +1,7 @@
 
 require(__dirname).test({
   expect : [
-    ["opentag", {"name": "R","attributes": {}}],
+    ["opentag", {"name": "R","attributes": {}, "isSelfClosing": false}],
     ["opencdata", undefined],
     ["cdata", " this is "],
     ["closecdata", undefined],
diff --git a/test/cdata-fake-end.js b/test/cdata-fake-end.js
index 07aeac4..ccafa1b 100644
--- a/test/cdata-fake-end.js
+++ b/test/cdata-fake-end.js
@@ -1,7 +1,7 @@
 
 var p = require(__dirname).test({
   expect : [
-    ["opentag", {"name": "R","attributes": {}}],
+    ["opentag", {"name": "R","attributes": {}, "isSelfClosing": false}],
     ["opencdata", undefined],
     ["cdata", "[[[[[[[[]]]]]]]]"],
     ["closecdata", undefined],
@@ -17,7 +17,7 @@ p.close();
 
 var p2 = require(__dirname).test({
   expect : [
-    ["opentag", {"name": "R","attributes": {}}],
+    ["opentag", {"name": "R","attributes": {}, "isSelfClosing": false}],
     ["opencdata", undefined],
     ["cdata", "[[[[[[[[]]]]]]]]"],
     ["closecdata", undefined],
diff --git a/test/cdata-multiple.js b/test/cdata-multiple.js
index dab2015..8e2f911 100644
--- a/test/cdata-multiple.js
+++ b/test/cdata-multiple.js
@@ -1,7 +1,7 @@
 
 require(__dirname).test({
   expect : [
-    ["opentag", {"name": "R","attributes": {}}],
+    ["opentag", {"name": "R","attributes": {}, "isSelfClosing": false}],
     ["opencdata", undefined],
     ["cdata", " this is "],
     ["closecdata", undefined],
diff --git a/test/cdata.js b/test/cdata.js
index 0f09cce..31a8a30 100644
--- a/test/cdata.js
+++ b/test/cdata.js
@@ -1,7 +1,7 @@
 require(__dirname).test({
   xml : "<r><![CDATA[ this is character data  ]]></r>",
   expect : [
-    ["opentag", {"name": "R","attributes": {}}],
+    ["opentag", {"name": "R","attributes": {}, "isSelfClosing": false}],
     ["opencdata", undefined],
     ["cdata", " this is character data  "],
     ["closecdata", undefined],
diff --git a/test/cyrillic.js b/test/cyrillic.js
new file mode 100644
index 0000000..f05dd1b
--- /dev/null
+++ b/test/cyrillic.js
@@ -0,0 +1,8 @@
+require(__dirname).test({
+  xml: '<Р>тест</Р>',
+  expect: [
+    ['opentag', {'name':'Р', attributes:{}, isSelfClosing: false}],
+    ['text', 'тест'],
+    ['closetag', 'Р']
+  ]
+});
diff --git a/test/duplicate-attribute.js b/test/duplicate-attribute.js
new file mode 100644
index 0000000..a21eb41
--- /dev/null
+++ b/test/duplicate-attribute.js
@@ -0,0 +1,13 @@
+require(__dirname).test
+  ( { xml :
+      "<span id=\"hello\" id=\"there\"></span>"
+    , expect :
+      [ [ "attribute", { name: "ID", value: "hello" } ]
+      , [ "opentag", { name: "SPAN",
+                       attributes: { ID: "hello" }, isSelfClosing: false } ]
+      , [ "closetag", "SPAN" ]
+      ]
+    , strict : false
+    , opt : {}
+    }
+  )
diff --git a/test/entities.js b/test/entities.js
new file mode 100644
index 0000000..4901667
--- /dev/null
+++ b/test/entities.js
@@ -0,0 +1,10 @@
+require(__dirname).test({
+  xml: '<r>⌋ ' +
+       '♠ © → & ' +
+        '< < <  <   < > ℜ ℘ €</r>',
+  expect: [
+    ['opentag', {'name':'R', attributes:{}, isSelfClosing: false}],
+    ['text', '⌋ ♠ © → & < < <  <   < > ℜ ℘ €'],
+    ['closetag', 'R']
+  ]
+});
diff --git a/test/entity-mega.js b/test/entity-mega.js
new file mode 100644
index 0000000..4759a02
--- /dev/null
+++ b/test/entity-mega.js
@@ -0,0 +1,16 @@
+var sax = require('../');
+var xml = '<r>';
+var text = '';
+for (var i in sax.ENTITIES) {
+  xml += '&' + i + ';'
+  text += sax.ENTITIES[i]
+}
+xml += '</r>'
+require(__dirname).test({
+  xml: xml,
+  expect: [
+    ['opentag', {'name':'R', attributes:{}, isSelfClosing: false}],
+    ['text', text],
+    ['closetag', 'R']
+  ]
+});
diff --git a/test/issue-23.js b/test/issue-23.js
index e7991b2..ccbdc35 100644
--- a/test/issue-23.js
+++ b/test/issue-23.js
@@ -13,24 +13,24 @@ require(__dirname).test
       "</compileClassesResponse>"
 
     , expect :
-      [ [ "opentag", { name: "COMPILECLASSESRESPONSE", attributes: {} } ]
-      , [ "opentag", { name : "RESULT", attributes: {} } ]
-      , [ "opentag", { name: "BODYCRC", attributes: {} } ]
+      [ [ "opentag", { name: "COMPILECLASSESRESPONSE", attributes: {}, isSelfClosing: false } ]
+      , [ "opentag", { name : "RESULT", attributes: {}, isSelfClosing: false } ]
+      , [ "opentag", { name: "BODYCRC", attributes: {}, isSelfClosing: false } ]
       , [ "text", "653724009" ]
       , [ "closetag", "BODYCRC" ]
-      , [ "opentag", { name: "COLUMN", attributes: {} } ]
+      , [ "opentag", { name: "COLUMN", attributes: {}, isSelfClosing: false } ]
       , [ "text", "-1" ]
       , [ "closetag", "COLUMN" ]
-      , [ "opentag", { name: "ID", attributes: {} } ]
+      , [ "opentag", { name: "ID", attributes: {}, isSelfClosing: false } ]
       , [ "text", "01pG0000002KoSUIA0" ]
       , [ "closetag", "ID" ]
-      , [ "opentag", {name: "LINE", attributes: {} } ]
+      , [ "opentag", {name: "LINE", attributes: {}, isSelfClosing: false } ]
       , [ "text", "-1" ]
       , [ "closetag", "LINE" ]
-      , [ "opentag", {name: "NAME", attributes: {} } ]
+      , [ "opentag", {name: "NAME", attributes: {}, isSelfClosing: false } ]
       , [ "text", "CalendarController" ]
       , [ "closetag", "NAME" ]
-      , [ "opentag", {name: "SUCCESS", attributes: {} } ]
+      , [ "opentag", {name: "SUCCESS", attributes: {}, isSelfClosing: false } ]
       , [ "text", "true" ]
       , [ "closetag", "SUCCESS" ]
       , [ "closetag", "RESULT" ]
diff --git a/test/issue-30.js b/test/issue-30.js
index c2cc809..771b14e 100644
--- a/test/issue-30.js
+++ b/test/issue-30.js
@@ -8,11 +8,11 @@ require(__dirname).test
             "</xml>"
 
     , expect :
-      [ [ "opentag", { name: "xml", attributes: {} } ]
+      [ [ "opentag", { name: "xml", attributes: {}, isSelfClosing: false } ]
       , [ "text", "\n" ]
       , [ "comment", " \n  comment with a single dash- in it\n" ]
       , [ "text", "\n" ]
-      , [ "opentag", { name: "data", attributes: {} } ]
+      , [ "opentag", { name: "data", attributes: {}, isSelfClosing: true } ]
       , [ "closetag", "data" ]
       , [ "text", "\n" ]
       , [ "closetag", "xml" ]
diff --git a/test/issue-35.js b/test/issue-35.js
index 7c521c5..64d67b3 100644
--- a/test/issue-35.js
+++ b/test/issue-35.js
@@ -4,7 +4,7 @@ require(__dirname).test
             "</xml>"
 
     , expect :
-      [ [ "opentag", { name: "xml", attributes: {} } ]
+      [ [ "opentag", { name: "xml", attributes: {}, isSelfClosing: false } ]
       , [ "text", "\r\r\n" ]
       , [ "closetag", "xml" ]
       ]
diff --git a/test/issue-47.js b/test/issue-47.js
index 911c7d0..661584a 100644
--- a/test/issue-47.js
+++ b/test/issue-47.js
@@ -1,12 +1,11 @@
 // https://github.com/isaacs/sax-js/issues/47
 require(__dirname).test
   ( { xml : '<a href="query.svc?x=1&y=2&z=3"/>'
-    , expect : [ 
-        [ "attribute", { name:'href', value:"query.svc?x=1&y=2&z=3"} ],
-        [ "opentag", { name: "a", attributes: { href:"query.svc?x=1&y=2&z=3"} } ],
-        [ "closetag", "a" ]
+    , expect : [
+        [ "attribute", { name:'HREF', value:"query.svc?x=1&y=2&z=3"} ],
+        [ "opentag", { name: "A", attributes: { HREF:"query.svc?x=1&y=2&z=3"}, isSelfClosing: true } ],
+        [ "closetag", "A" ]
       ]
-    , strict : true
     , opt : {}
     }
   )
diff --git a/test/issue-49.js b/test/issue-49.js
index 2964325..ff2fbf7 100644
--- a/test/issue-49.js
+++ b/test/issue-49.js
@@ -2,8 +2,8 @@
 require(__dirname).test
   ( { xml : "<xml><script>hello world</script></xml>"
     , expect :
-      [ [ "opentag", { name: "xml", attributes: {} } ]
-      , [ "opentag", { name: "script", attributes: {} } ]
+      [ [ "opentag", { name: "xml", attributes: {}, isSelfClosing: false } ]
+      , [ "opentag", { name: "script", attributes: {}, isSelfClosing: false } ]
       , [ "text", "hello world" ]
       , [ "closetag", "script" ]
       , [ "closetag", "xml" ]
@@ -16,8 +16,8 @@ require(__dirname).test
 require(__dirname).test
   ( { xml : "<xml><script><![CDATA[hello world]]></script></xml>"
     , expect :
-      [ [ "opentag", { name: "xml", attributes: {} } ]
-      , [ "opentag", { name: "script", attributes: {} } ]
+      [ [ "opentag", { name: "xml", attributes: {}, isSelfClosing: false } ]
+      , [ "opentag", { name: "script", attributes: {}, isSelfClosing: false } ]
       , [ "opencdata", undefined ]
       , [ "cdata", "hello world" ]
       , [ "closecdata", undefined ]
diff --git a/test/issue-84.js b/test/issue-84.js
new file mode 100644
index 0000000..0e7ee69
--- /dev/null
+++ b/test/issue-84.js
@@ -0,0 +1,13 @@
+// https://github.com/isaacs/sax-js/issues/49
+require(__dirname).test
+  ( { xml : "<?has unbalanced \"quotes?><xml>body</xml>"
+    , expect :
+      [ [ "processinginstruction", { name: "has", body: "unbalanced \"quotes" } ],
+        [ "opentag", { name: "xml", attributes: {}, isSelfClosing: false } ]
+      , [ "text", "body" ]
+      , [ "closetag", "xml" ]
+      ]
+    , strict : false
+    , opt : { lowercasetags: true, noscript: true }
+    }
+  )
diff --git a/test/script-close-better.js b/test/script-close-better.js
new file mode 100644
index 0000000..f4887b9
--- /dev/null
+++ b/test/script-close-better.js
@@ -0,0 +1,12 @@
+require(__dirname).test({
+  xml : "<html><head><script>'<div>foo</div></'</script></head></html>",
+  expect : [
+    ["opentag", {"name": "HTML","attributes": {}, isSelfClosing: false}],
+    ["opentag", {"name": "HEAD","attributes": {}, isSelfClosing: false}],
+    ["opentag", {"name": "SCRIPT","attributes": {}, isSelfClosing: false}],
+    ["script", "'<div>foo</div></'"],
+    ["closetag", "SCRIPT"],
+    ["closetag", "HEAD"],
+    ["closetag", "HTML"]
+  ]
+});
diff --git a/test/script.js b/test/script.js
index 464c051..fbda1f6 100644
--- a/test/script.js
+++ b/test/script.js
@@ -1,9 +1,9 @@
 require(__dirname).test({
   xml : "<html><head><script>if (1 < 0) { console.log('elo there'); }</script></head></html>",
   expect : [
-    ["opentag", {"name": "HTML","attributes": {}}],
-    ["opentag", {"name": "HEAD","attributes": {}}],
-    ["opentag", {"name": "SCRIPT","attributes": {}}],
+    ["opentag", {"name": "HTML","attributes": {}, "isSelfClosing": false}],
+    ["opentag", {"name": "HEAD","attributes": {}, "isSelfClosing": false}],
+    ["opentag", {"name": "SCRIPT","attributes": {}, "isSelfClosing": false}],
     ["script", "if (1 < 0) { console.log('elo there'); }"],
     ["closetag", "SCRIPT"],
     ["closetag", "HEAD"],
diff --git a/test/self-closing-child-strict.js b/test/self-closing-child-strict.js
index ce9c045..3d6e985 100644
--- a/test/self-closing-child-strict.js
+++ b/test/self-closing-child-strict.js
@@ -12,21 +12,25 @@ require(__dirname).test({
   expect : [
     ["opentag", {
      "name": "root",
-     "attributes": {}
+     "attributes": {},
+     "isSelfClosing": false
     }],
     ["opentag", {
      "name": "child",
-     "attributes": {}
+     "attributes": {},
+     "isSelfClosing": false
     }],
     ["opentag", {
      "name": "haha",
-     "attributes": {}
+     "attributes": {},
+     "isSelfClosing": true
     }],
     ["closetag", "haha"],
     ["closetag", "child"],
     ["opentag", {
      "name": "monkey",
-     "attributes": {}
+     "attributes": {},
+     "isSelfClosing": false
     }],
     ["text", "=(|)"],
     ["closetag", "monkey"],
diff --git a/test/self-closing-child.js b/test/self-closing-child.js
index bc6b52b..f31c366 100644
--- a/test/self-closing-child.js
+++ b/test/self-closing-child.js
@@ -12,21 +12,25 @@ require(__dirname).test({
   expect : [
     ["opentag", {
      "name": "ROOT",
-     "attributes": {}
+     "attributes": {},
+     "isSelfClosing": false
     }],
     ["opentag", {
      "name": "CHILD",
-     "attributes": {}
+     "attributes": {},
+     "isSelfClosing": false
     }],
     ["opentag", {
      "name": "HAHA",
-     "attributes": {}
+     "attributes": {},
+     "isSelfClosing": true
     }],
     ["closetag", "HAHA"],
     ["closetag", "CHILD"],
     ["opentag", {
      "name": "MONKEY",
-     "attributes": {}
+     "attributes": {},
+     "isSelfClosing": false
     }],
     ["text", "=(|)"],
     ["closetag", "MONKEY"],
diff --git a/test/self-closing-tag.js b/test/self-closing-tag.js
index b2c5736..d1d8b7c 100644
--- a/test/self-closing-tag.js
+++ b/test/self-closing-tag.js
@@ -9,14 +9,14 @@ require(__dirname).test({
     "</monkey>"+
   "</root>  ",
   expect : [
-    ["opentag", {name:"ROOT", attributes:{}}],
-    ["opentag", {name:"HAHA", attributes:{}}],
+    ["opentag", {name:"ROOT", attributes:{}, isSelfClosing: false}],
+    ["opentag", {name:"HAHA", attributes:{}, isSelfClosing: true}],
     ["closetag", "HAHA"],
-    ["opentag", {name:"HAHA", attributes:{}}],
+    ["opentag", {name:"HAHA", attributes:{}, isSelfClosing: true}],
     ["closetag", "HAHA"],
     // ["opentag", {name:"HAHA", attributes:{}}],
     // ["closetag", "HAHA"],
-    ["opentag", {name:"MONKEY", attributes:{}}],
+    ["opentag", {name:"MONKEY", attributes:{}, isSelfClosing: false}],
     ["text", "=(|)"],
     ["closetag", "MONKEY"],
     ["closetag", "ROOT"]
diff --git a/test/stray-ending.js b/test/stray-ending.js
index 6b0aa7f..bec467b 100644
--- a/test/stray-ending.js
+++ b/test/stray-ending.js
@@ -4,8 +4,8 @@ require(__dirname).test
   ( { xml :
       "<a><b></c></b></a>"
     , expect :
-      [ [ "opentag", { name: "A", attributes: {} } ]
-      , [ "opentag", { name: "B", attributes: {} } ]
+      [ [ "opentag", { name: "A", attributes: {}, isSelfClosing: false } ]
+      , [ "opentag", { name: "B", attributes: {}, isSelfClosing: false } ]
       , [ "text", "</c>" ]
       , [ "closetag", "B" ]
       , [ "closetag", "A" ]
diff --git a/test/trailing-attribute-no-value.js b/test/trailing-attribute-no-value.js
new file mode 100644
index 0000000..222837f
--- /dev/null
+++ b/test/trailing-attribute-no-value.js
@@ -0,0 +1,10 @@
+
+require(__dirname).test({
+  xml :
+  "<root attrib>",
+  expect : [
+    ["attribute", {name:"ATTRIB", value:"attrib"}],
+    ["opentag", {name:"ROOT", attributes:{"ATTRIB":"attrib"}, isSelfClosing: false}]
+  ],
+  opt : { trim : true }
+});
diff --git a/test/trailing-non-whitespace.js b/test/trailing-non-whitespace.js
index 3e1fb2e..619578b 100644
--- a/test/trailing-non-whitespace.js
+++ b/test/trailing-non-whitespace.js
@@ -4,7 +4,8 @@ require(__dirname).test({
   expect : [
     ["opentag", {
      "name": "SPAN",
-     "attributes": {}
+     "attributes": {},
+     isSelfClosing: false
     }],
     ["text", "Welcome,"],
     ["closetag", "SPAN"],
diff --git a/test/unclosed-root.js b/test/unclosed-root.js
new file mode 100644
index 0000000..f4eeac6
--- /dev/null
+++ b/test/unclosed-root.js
@@ -0,0 +1,11 @@
+require(__dirname).test
+  ( { xml : "<root>"
+
+    , expect :
+      [ [ "opentag", { name: "root", attributes: {}, isSelfClosing: false } ]
+      , [ "error", "Unclosed root tag\nLine: 0\nColumn: 6\nChar: " ]
+      ]
+    , strict : true
+    , opt : {}
+    }
+  )
diff --git a/test/unquoted.js b/test/unquoted.js
index dbeb638..b3a9a81 100644
--- a/test/unquoted.js
+++ b/test/unquoted.js
@@ -7,7 +7,8 @@ require(__dirname).test
       [ [ "attribute", { name: "CLASS", value: "test" } ]
       , [ "attribute", { name: "HELLO", value: "world" } ]
       , [ "opentag", { name: "SPAN",
-                       attributes: { CLASS: "test", HELLO: "world" } } ]
+                       attributes: { CLASS: "test", HELLO: "world" },
+                       isSelfClosing: false } ]
       , [ "closetag", "SPAN" ]
       ]
     , strict : false
diff --git a/test/utf8-split.js b/test/utf8-split.js
new file mode 100644
index 0000000..e22bc10
--- /dev/null
+++ b/test/utf8-split.js
@@ -0,0 +1,32 @@
+var assert = require('assert')
+var saxStream = require('../lib/sax').createStream()
+
+var b = new Buffer('误')
+
+saxStream.on('text', function(text) {
+  assert.equal(text, b.toString())
+})
+
+saxStream.write(new Buffer('<test><a>'))
+saxStream.write(b.slice(0, 1))
+saxStream.write(b.slice(1))
+saxStream.write(new Buffer('</a><b>'))
+saxStream.write(b.slice(0, 2))
+saxStream.write(b.slice(2))
+saxStream.write(new Buffer('</b><c>'))
+saxStream.write(b)
+saxStream.write(new Buffer('</c>'))
+saxStream.write(Buffer.concat([new Buffer('<d>'), b.slice(0, 1)]))
+saxStream.end(Buffer.concat([b.slice(1), new Buffer('</d></test>')]))
+
+var saxStream2 = require('../lib/sax').createStream()
+
+saxStream2.on('text', function(text) {
+  assert.equal(text, '�')
+});
+
+saxStream2.write(new Buffer('<e>'));
+saxStream2.write(new Buffer([0xC0]));
+saxStream2.write(new Buffer('</e>'));
+saxStream2.write(Buffer.concat([new Buffer('<f>'), b.slice(0,1)]));
+saxStream2.end();
diff --git a/test/xmlns-issue-41.js b/test/xmlns-issue-41.js
index 596d82b..17ab45a 100644
--- a/test/xmlns-issue-41.js
+++ b/test/xmlns-issue-41.js
@@ -48,6 +48,7 @@ var t = require(__dirname)
             }
           }
         , ns: {"a": "http://ATTRIBUTE"}
+        , isSelfClosing: true
         }
       ]
     , ["closetag", "parent"]
diff --git a/test/xmlns-rebinding.js b/test/xmlns-rebinding.js
index f464876..07e0425 100644
--- a/test/xmlns-rebinding.js
+++ b/test/xmlns-rebinding.js
@@ -20,20 +20,23 @@ require(__dirname).test
                         , "xmlns:y": { name: "xmlns:y", value: "y1", uri: "http://www.w3.org/2000/xmlns/", prefix: "xmlns", local: "y" }
                         , "x:a": { name: "x:a", value: "x1", uri: "x1", prefix: "x", local: "a" }
                         , "y:a": { name: "y:a", value: "y1", uri: "y1", prefix: "y", local: "a" } },
-            ns: { x: 'x1', y: 'y1' } } ]
+            ns: { x: 'x1', y: 'y1' },
+            isSelfClosing: false } ]
 
       , [ "opennamespace", { prefix: "x", uri: "x2" } ]
       , [ "attribute", { name: "xmlns:x", value: "x2", uri: "http://www.w3.org/2000/xmlns/", prefix: "xmlns", local: "x" } ]
       , [ "opentag", { name: "rebind", uri: "", prefix: "", local: "rebind",
             attributes: { "xmlns:x": { name: "xmlns:x", value: "x2", uri: "http://www.w3.org/2000/xmlns/", prefix: "xmlns", local: "x" } },
-            ns: { x: 'x2' } } ]
+            ns: { x: 'x2' },
+            isSelfClosing: false } ]
 
       , [ "attribute", { name: "x:a", value: "x2", uri: "x2", prefix: "x", local: "a" } ]
       , [ "attribute", { name: "y:a", value: "y1", uri: "y1", prefix: "y", local: "a" } ]
       , [ "opentag", { name: "check", uri: "", prefix: "", local: "check",
             attributes: { "x:a": { name: "x:a", value: "x2", uri: "x2", prefix: "x", local: "a" }
                         , "y:a": { name: "y:a", value: "y1", uri: "y1", prefix: "y", local: "a" } },
-            ns: { x: 'x2' } } ]
+            ns: { x: 'x2' },
+            isSelfClosing: true } ]
 
       , [ "closetag", "check" ]
 
@@ -45,7 +48,8 @@ require(__dirname).test
       , [ "opentag", { name: "check", uri: "", prefix: "", local: "check",
             attributes: { "x:a": { name: "x:a", value: "x1", uri: "x1", prefix: "x", local: "a" }
                         , "y:a": { name: "y:a", value: "y1", uri: "y1", prefix: "y", local: "a" } },
-            ns: { x: 'x1', y: 'y1' } } ]
+            ns: { x: 'x1', y: 'y1' },
+            isSelfClosing: true } ]
       , [ "closetag", "check" ]
 
       , [ "closetag", "root" ]
diff --git a/test/xmlns-strict.js b/test/xmlns-strict.js
index 4ad615b..b5e3e51 100644
--- a/test/xmlns-strict.js
+++ b/test/xmlns-strict.js
@@ -14,12 +14,12 @@ require(__dirname).test
 
     , expect :
       [ [ "opentag", { name: "root", prefix: "", local: "root", uri: "",
-            attributes: {}, ns: {} } ]
+            attributes: {}, ns: {}, isSelfClosing: false } ]
 
       , [ "attribute", { name: "attr", value: "normal", prefix: "", local: "attr", uri: "" } ]
       , [ "opentag", { name: "plain", prefix: "", local: "plain", uri: "",
             attributes: { "attr": { name: "attr", value: "normal", uri: "", prefix: "", local: "attr", uri: "" } },
-            ns: {} } ]
+            ns: {}, isSelfClosing: true } ]
       , [ "closetag", "plain" ]
 
       , [ "opennamespace", { prefix: "", uri: "uri:default" } ]
@@ -27,11 +27,12 @@ require(__dirname).test
       , [ "attribute", { name: "xmlns", value: "uri:default", prefix: "xmlns", local: "", uri: "http://www.w3.org/2000/xmlns/" } ]
       , [ "opentag", { name: "ns1", prefix: "", local: "ns1", uri: "uri:default",
             attributes: { "xmlns": { name: "xmlns", value: "uri:default", prefix: "xmlns", local: "", uri: "http://www.w3.org/2000/xmlns/" } },
-            ns: { "": "uri:default" } } ]
+            ns: { "": "uri:default" }, isSelfClosing: false } ]
 
-      , [ "attribute", { name: "attr", value: "normal", prefix: "", local: "attr", uri: "uri:default" } ]
+      , [ "attribute", { name: "attr", value: "normal", prefix: "", local: "attr", uri: "" } ]
       , [ "opentag", { name: "plain", prefix: "", local: "plain", uri: "uri:default", ns: { '': 'uri:default' },
-            attributes: { "attr": { name: "attr", value: "normal", prefix: "", local: "attr", uri: "uri:default" } } } ]
+            attributes: { "attr": { name: "attr", value: "normal", prefix: "", local: "attr", uri: "" } },
+            isSelfClosing: true } ]
       , [ "closetag", "plain" ]
 
       , [ "closetag", "ns1" ]
@@ -44,18 +45,20 @@ require(__dirname).test
 
       , [ "opentag", { name: "ns2", prefix: "", local: "ns2", uri: "",
             attributes: { "xmlns:a": { name: "xmlns:a", value: "uri:nsa", prefix: "xmlns", local: "a", uri: "http://www.w3.org/2000/xmlns/" } },
-            ns: { a: "uri:nsa" } } ]
+            ns: { a: "uri:nsa" }, isSelfClosing: false } ]
 
       , [ "attribute", { name: "attr", value: "normal", prefix: "", local: "attr", uri: "" } ]
       , [ "opentag", { name: "plain", prefix: "", local: "plain", uri: "",
             attributes: { "attr": { name: "attr", value: "normal", prefix: "", local: "attr", uri: "" } },
-            ns: { a: 'uri:nsa' } } ]
+            ns: { a: 'uri:nsa' },
+            isSelfClosing: true } ]
       , [ "closetag", "plain" ]
 
       , [ "attribute", { name: "a:attr", value: "namespaced", prefix: "a", local: "attr", uri: "uri:nsa" } ]
       , [ "opentag", { name: "a:ns", prefix: "a", local: "ns", uri: "uri:nsa",
             attributes: { "a:attr": { name: "a:attr", value: "namespaced", prefix: "a", local: "attr", uri: "uri:nsa" } },
-            ns: { a: 'uri:nsa' } } ]
+            ns: { a: 'uri:nsa' },
+            isSelfClosing: true } ]
       , [ "closetag", "a:ns" ]
 
       , [ "closetag", "ns2" ]
diff --git a/test/xmlns-unbound-element.js b/test/xmlns-unbound-element.js
new file mode 100644
index 0000000..9d031a2
--- /dev/null
+++ b/test/xmlns-unbound-element.js
@@ -0,0 +1,33 @@
+require(__dirname).test(
+  { strict : true
+  , opt : { xmlns: true }
+  , expect :
+    [ [ "error", "Unbound namespace prefix: \"unbound:root\"\nLine: 0\nColumn: 15\nChar: >"]
+    , [ "opentag", { name: "unbound:root", uri: "unbound", prefix: "unbound", local: "root"
+        , attributes: {}, ns: {}, isSelfClosing: true } ]
+    , [ "closetag", "unbound:root" ]
+    ]
+  }
+).write("<unbound:root/>");
+
+require(__dirname).test(
+  { strict : true
+  , opt : { xmlns: true }
+  , expect :
+    [ [ "opennamespace", { prefix: "unbound", uri: "someuri" } ]
+    , [ "attribute", { name: 'xmlns:unbound', value: 'someuri'
+      , prefix: 'xmlns', local: 'unbound'
+      , uri: 'http://www.w3.org/2000/xmlns/' } ]
+    , [ "opentag", { name: "unbound:root", uri: "someuri", prefix: "unbound", local: "root"
+          , attributes: { 'xmlns:unbound': {
+              name: 'xmlns:unbound'
+            , value: 'someuri'
+            , prefix: 'xmlns'
+            , local: 'unbound'
+            , uri: 'http://www.w3.org/2000/xmlns/' } }
+      , ns: { "unbound": "someuri" }, isSelfClosing: true } ]
+    , [ "closetag", "unbound:root" ]
+    , [ "closenamespace", { prefix: 'unbound', uri: 'someuri' }]
+    ]
+  }
+).write("<unbound:root xmlns:unbound=\"someuri\"/>");
diff --git a/test/xmlns-unbound.js b/test/xmlns-unbound.js
index 2944b87..b740e26 100644
--- a/test/xmlns-unbound.js
+++ b/test/xmlns-unbound.js
@@ -8,7 +8,7 @@ require(__dirname).test(
     , [ "attribute", { name: "unbound:attr", value: "value", uri: "unbound", prefix: "unbound", local: "attr" } ]
     , [ "opentag", { name: "root", uri: "", prefix: "", local: "root",
           attributes: { "unbound:attr": { name: "unbound:attr", value: "value", uri: "unbound", prefix: "unbound", local: "attr" } },
-          ns: {} } ]
+          ns: {}, isSelfClosing: true } ]
     , [ "closetag", "root" ]
     ]
   }
diff --git a/test/xmlns-xml-default-ns.js b/test/xmlns-xml-default-ns.js
new file mode 100644
index 0000000..b1984d2
--- /dev/null
+++ b/test/xmlns-xml-default-ns.js
@@ -0,0 +1,31 @@
+var xmlns_attr =
+{
+    name: "xmlns", value: "http://foo", prefix: "xmlns",
+    local: "", uri : "http://www.w3.org/2000/xmlns/"
+};
+
+var attr_attr =
+{
+    name: "attr", value: "bar", prefix: "",
+    local : "attr",  uri : ""
+};
+
+
+require(__dirname).test
+  ( { xml :
+      "<elm xmlns='http://foo' attr='bar'/>"
+    , expect :
+      [ [ "opennamespace", { prefix: "", uri: "http://foo" } ]
+      , [ "attribute", xmlns_attr ]
+      , [ "attribute", attr_attr ]
+      , [ "opentag", { name: "elm", prefix: "", local: "elm", uri : "http://foo",
+                       ns : { "" : "http://foo" },
+                       attributes: { xmlns: xmlns_attr, attr: attr_attr },
+                       isSelfClosing: true } ]
+      , [ "closetag", "elm" ]
+      , [ "closenamespace", { prefix: "", uri: "http://foo"} ]
+      ]
+    , strict : true
+    , opt : {xmlns: true}
+    }
+  )
diff --git a/test/xmlns-xml-default-prefix-attribute.js b/test/xmlns-xml-default-prefix-attribute.js
index 16da771..e41f218 100644
--- a/test/xmlns-xml-default-prefix-attribute.js
+++ b/test/xmlns-xml-default-prefix-attribute.js
@@ -24,6 +24,7 @@ require(__dirname).test(
             }
           }
         , ns: {}
+        , isSelfClosing: true
         }
       ]
     , ["closetag", "root"]
diff --git a/test/xmlns-xml-default-prefix.js b/test/xmlns-xml-default-prefix.js
index 9a1ce1b..a85b478 100644
--- a/test/xmlns-xml-default-prefix.js
+++ b/test/xmlns-xml-default-prefix.js
@@ -9,6 +9,7 @@ require(__dirname).test(
         , local: "root"
         , attributes: {}
         , ns: {}
+        , isSelfClosing: true
         }
       ]
     , ["closetag", "xml:root"]
diff --git a/test/xmlns-xml-default-redefine.js b/test/xmlns-xml-default-redefine.js
index 1eba9c7..d35d5a0 100644
--- a/test/xmlns-xml-default-redefine.js
+++ b/test/xmlns-xml-default-redefine.js
@@ -29,6 +29,7 @@ require(__dirname).test(
             }
           }
         , ns: {}
+        , isSelfClosing: true
         }
       ]
     , ["closetag", "xml:root"]

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/collab-maint/sax.js.git



More information about the Pkg-javascript-commits mailing list