sax 0.5.4 → 0.5.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/sax.js CHANGED
@@ -133,11 +133,24 @@ function clearBuffers (parser) {
133
133
  }
134
134
  }
135
135
 
136
+ function flushBuffers (parser) {
137
+ closeText(parser)
138
+ if (parser.cdata !== "") {
139
+ emitNode(parser, "oncdata", parser.cdata)
140
+ parser.cdata = ""
141
+ }
142
+ if (parser.script !== "") {
143
+ emitNode(parser, "onscript", parser.script)
144
+ parser.script = ""
145
+ }
146
+ }
147
+
136
148
  SAXParser.prototype =
137
149
  { end: function () { end(this) }
138
150
  , write: write
139
151
  , resume: function () { this.error = null; return this }
140
152
  , close: function () { return this.write(null) }
153
+ , flush: function () { flushBuffers(this) }
141
154
  }
142
155
 
143
156
  try {
@@ -179,6 +192,8 @@ function SAXStream (strict, opt) {
179
192
  me._parser.error = null
180
193
  }
181
194
 
195
+ this._decoder = null;
196
+
182
197
  streamWraps.forEach(function (ev) {
183
198
  Object.defineProperty(me, "on" + ev, {
184
199
  get: function () { return me._parser["on" + ev] },
@@ -199,13 +214,23 @@ SAXStream.prototype = Object.create(Stream.prototype,
199
214
  { constructor: { value: SAXStream } })
200
215
 
201
216
  SAXStream.prototype.write = function (data) {
217
+ if (typeof Buffer === 'function' &&
218
+ typeof Buffer.isBuffer === 'function' &&
219
+ Buffer.isBuffer(data)) {
220
+ if (!this._decoder) {
221
+ var SD = require('string_decoder').StringDecoder
222
+ this._decoder = new SD('utf8')
223
+ }
224
+ data = this._decoder.write(data);
225
+ }
226
+
202
227
  this._parser.write(data.toString())
203
228
  this.emit("data", data)
204
229
  return true
205
230
  }
206
231
 
207
232
  SAXStream.prototype.end = function (chunk) {
208
- if (chunk && chunk.length) this._parser.write(chunk.toString())
233
+ if (chunk && chunk.length) this.write(chunk)
209
234
  this._parser.end()
210
235
  return true
211
236
  }
@@ -309,6 +334,7 @@ sax.STATE =
309
334
  , ATTRIB_NAME_SAW_WHITE : S++ // <a foo _
310
335
  , ATTRIB_VALUE : S++ // <a foo=
311
336
  , ATTRIB_VALUE_QUOTED : S++ // <a foo="bar
337
+ , ATTRIB_VALUE_CLOSED : S++ // <a foo="bar"
312
338
  , ATTRIB_VALUE_UNQUOTED : S++ // <a foo=bar
313
339
  , ATTRIB_VALUE_ENTITY_Q : S++ // <foo bar="&quot;"
314
340
  , ATTRIB_VALUE_ENTITY_U : S++ // <foo bar=&quot;
@@ -621,7 +647,7 @@ function error (parser, er) {
621
647
 
622
648
  function end (parser) {
623
649
  if (!parser.closedRoot) strictFail(parser, "Unclosed root tag")
624
- if (parser.state !== S.TEXT) error(parser, "Unexpected end")
650
+ if ((parser.state !== S.BEGIN) && (parser.state !== S.TEXT)) error(parser, "Unexpected end")
625
651
  closeText(parser)
626
652
  parser.c = ""
627
653
  parser.closed = true
@@ -646,14 +672,14 @@ function newTag (parser) {
646
672
  parser.attribList.length = 0
647
673
  }
648
674
 
649
- function qname (name) {
675
+ function qname (name, attribute) {
650
676
  var i = name.indexOf(":")
651
677
  , qualName = i < 0 ? [ "", name ] : name.split(":")
652
678
  , prefix = qualName[0]
653
679
  , local = qualName[1]
654
680
 
655
681
  // <x "xmlns"="http://foo">
656
- if (name === "xmlns") {
682
+ if (attribute && name === "xmlns") {
657
683
  prefix = "xmlns"
658
684
  local = ""
659
685
  }
@@ -670,7 +696,7 @@ function attrib (parser) {
670
696
  }
671
697
 
672
698
  if (parser.opt.xmlns) {
673
- var qn = qname(parser.attribName)
699
+ var qn = qname(parser.attribName, true)
674
700
  , prefix = qn.prefix
675
701
  , local = qn.local
676
702
 
@@ -743,7 +769,7 @@ function openTag (parser, selfClosing) {
743
769
  var nv = parser.attribList[i]
744
770
  var name = nv[0]
745
771
  , value = nv[1]
746
- , qualName = qname(name)
772
+ , qualName = qname(name, true)
747
773
  , prefix = qualName.prefix
748
774
  , local = qualName.local
749
775
  , uri = prefix == "" ? "" : (tag.ns[prefix] || "")
@@ -1225,7 +1251,20 @@ function write (chunk) {
1225
1251
  }
1226
1252
  attrib(parser)
1227
1253
  parser.q = ""
1228
- parser.state = S.ATTRIB
1254
+ parser.state = S.ATTRIB_VALUE_CLOSED
1255
+ continue
1256
+
1257
+ case S.ATTRIB_VALUE_CLOSED:
1258
+ if (is(whitespace, c)) {
1259
+ parser.state = S.ATTRIB
1260
+ } else if (c === ">") openTag(parser)
1261
+ else if (c === "/") parser.state = S.OPEN_TAG_SLASH
1262
+ else if (is(nameStart, c)) {
1263
+ strictFail(parser, "No whitespace between attributes")
1264
+ parser.attribName = c
1265
+ parser.attribValue = ""
1266
+ parser.state = S.ATTRIB_NAME
1267
+ } else strictFail(parser, "Invalid attribute name")
1229
1268
  continue
1230
1269
 
1231
1270
  case S.ATTRIB_VALUE_UNQUOTED:
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "sax",
3
3
  "description": "An evented streaming XML parser in JavaScript",
4
4
  "author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
5
- "version": "0.5.4",
5
+ "version": "0.5.8",
6
6
  "main": "lib/sax.js",
7
7
  "license": "BSD",
8
8
  "scripts": {
@@ -0,0 +1,75 @@
1
+ // non-strict: no error
2
+ require(__dirname).test
3
+ ( { xml : '<root attr1="first"attr2="second"/>'
4
+
5
+ , expect :
6
+ [ [ "attribute", { name: 'attr1', value: 'first' } ]
7
+ , [ "attribute", { name: 'attr2', value: 'second' } ]
8
+ , [ "opentag", { name: "root", attributes: {attr1: 'first', attr2: 'second'}, isSelfClosing: true } ]
9
+ , [ "closetag", "root" ]
10
+ ]
11
+ , strict : false
12
+ , opt : { lowercase: true }
13
+ }
14
+ )
15
+
16
+ // strict: should give an error, but still parse
17
+ require(__dirname).test
18
+ ( { xml : '<root attr1="first"attr2="second"/>'
19
+
20
+ , expect :
21
+ [ [ "attribute", { name: 'attr1', value: 'first' } ]
22
+ , [ "error", "No whitespace between attributes\nLine: 0\nColumn: 20\nChar: a" ]
23
+ , [ "attribute", { name: 'attr2', value: 'second' } ]
24
+ , [ "opentag", { name: "root", attributes: {attr1: 'first', attr2: 'second'}, isSelfClosing: true } ]
25
+ , [ "closetag", "root" ]
26
+ ]
27
+ , strict : true
28
+ , opt : { }
29
+ }
30
+ )
31
+
32
+ // strict: other cases should still pass
33
+ require(__dirname).test
34
+ ( { xml : '<root attr1="first" attr2="second"/>'
35
+
36
+ , expect :
37
+ [ [ "attribute", { name: 'attr1', value: 'first' } ]
38
+ , [ "attribute", { name: 'attr2', value: 'second' } ]
39
+ , [ "opentag", { name: "root", attributes: {attr1: 'first', attr2: 'second'}, isSelfClosing: true } ]
40
+ , [ "closetag", "root" ]
41
+ ]
42
+ , strict : true
43
+ , opt : { }
44
+ }
45
+ )
46
+
47
+ // strict: other cases should still pass
48
+ require(__dirname).test
49
+ ( { xml : '<root attr1="first"\nattr2="second"/>'
50
+
51
+ , expect :
52
+ [ [ "attribute", { name: 'attr1', value: 'first' } ]
53
+ , [ "attribute", { name: 'attr2', value: 'second' } ]
54
+ , [ "opentag", { name: "root", attributes: {attr1: 'first', attr2: 'second'}, isSelfClosing: true } ]
55
+ , [ "closetag", "root" ]
56
+ ]
57
+ , strict : true
58
+ , opt : { }
59
+ }
60
+ )
61
+
62
+ // strict: other cases should still pass
63
+ require(__dirname).test
64
+ ( { xml : '<root attr1="first" attr2="second"/>'
65
+
66
+ , expect :
67
+ [ [ "attribute", { name: 'attr1', value: 'first' } ]
68
+ , [ "attribute", { name: 'attr2', value: 'second' } ]
69
+ , [ "opentag", { name: "root", attributes: {attr1: 'first', attr2: 'second'}, isSelfClosing: true } ]
70
+ , [ "closetag", "root" ]
71
+ ]
72
+ , strict : true
73
+ , opt : { }
74
+ }
75
+ )
@@ -0,0 +1,5 @@
1
+ var assert = require('assert');
2
+ var saxStream = require('../lib/sax').createStream();
3
+ assert.doesNotThrow(function() {
4
+ saxStream.end();
5
+ });
package/test/flush.js ADDED
@@ -0,0 +1,13 @@
1
+ var parser = require(__dirname).test({
2
+ expect: [
3
+ ['opentag', {'name':'T', attributes:{}, isSelfClosing: false}],
4
+ ['text', 'flush'],
5
+ ['text', 'rest'],
6
+ ['closetag', 'T'],
7
+ ]
8
+ });
9
+
10
+ parser.write('<T>flush');
11
+ parser.flush();
12
+ parser.write('rest</T>');
13
+ parser.close();
@@ -0,0 +1,32 @@
1
+ var assert = require('assert')
2
+ var saxStream = require('../lib/sax').createStream()
3
+
4
+ var b = new Buffer('误')
5
+
6
+ saxStream.on('text', function(text) {
7
+ assert.equal(text, b.toString())
8
+ })
9
+
10
+ saxStream.write(new Buffer('<test><a>'))
11
+ saxStream.write(b.slice(0, 1))
12
+ saxStream.write(b.slice(1))
13
+ saxStream.write(new Buffer('</a><b>'))
14
+ saxStream.write(b.slice(0, 2))
15
+ saxStream.write(b.slice(2))
16
+ saxStream.write(new Buffer('</b><c>'))
17
+ saxStream.write(b)
18
+ saxStream.write(new Buffer('</c>'))
19
+ saxStream.write(Buffer.concat([new Buffer('<d>'), b.slice(0, 1)]))
20
+ saxStream.end(Buffer.concat([b.slice(1), new Buffer('</d></test>')]))
21
+
22
+ var saxStream2 = require('../lib/sax').createStream()
23
+
24
+ saxStream2.on('text', function(text) {
25
+ assert.equal(text, '�')
26
+ });
27
+
28
+ saxStream2.write(new Buffer('<e>'));
29
+ saxStream2.write(new Buffer([0xC0]));
30
+ saxStream2.write(new Buffer('</e>'));
31
+ saxStream2.write(Buffer.concat([new Buffer('<f>'), b.slice(0,1)]));
32
+ saxStream2.end();
@@ -0,0 +1,15 @@
1
+
2
+ require(__dirname).test
3
+ ( { xml :
4
+ "<xmlns/>"
5
+ , expect :
6
+ [ [ "opentag", { name: "xmlns", uri: "", prefix: "", local: "xmlns",
7
+ attributes: {}, ns: {},
8
+ isSelfClosing: true}
9
+ ],
10
+ ["closetag", "xmlns"]
11
+ ]
12
+ , strict : true
13
+ , opt : { xmlns: true }
14
+ }
15
+ );