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 +46 -7
- package/package.json +1 -1
- package/test/attribute-no-space.js +75 -0
- package/test/end_empty_stream.js +5 -0
- package/test/flush.js +13 -0
- package/test/utf8-split.js +32 -0
- package/test/xmlns-as-tag-name.js +15 -0
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.
|
|
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="""
|
|
314
340
|
, ATTRIB_VALUE_ENTITY_U : S++ // <foo bar="
|
|
@@ -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.
|
|
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
|
@@ -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
|
+
)
|
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
|
+
);
|