xml-toolkit 1.0.60 → 1.1.0
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/README.md +35 -45
- package/index.js +14 -7
- package/lib/XMLMarshaller.js +57 -24
- package/lib/XMLNode.js +1 -1
- package/lib/XMLParser.js +42 -13
- package/lib/XMLReader.js +44 -0
- package/lib/XMLSchema.js +11 -0
- package/lib/XMLSchemaBuiltIn.js +20 -5
- package/lib/XMLSchemaXml.js +0 -1
- package/lib/XMLSchemata.js +94 -11
- package/lib/XSAnyType.js +98 -0
- package/lib/{XMLPrinter.js → printer/Base.js} +19 -30
- package/lib/printer/XMLPrinter.js +39 -0
- package/lib/printer/XMLStreamPrinter.js +122 -0
- package/lib/simple/DT7.js +248 -0
- package/lib/simple/XSSimpleType.js +259 -0
- package/lib/simple/XSSimpleTypeBoolean.js +91 -0
- package/lib/simple/XSSimpleTypeDT.js +96 -0
- package/lib/simple/XSSimpleTypeDecimal.js +130 -0
- package/lib/simple/XSSimpleTypeFloatingPoint.js +80 -0
- package/lib/simple/XSSimpleTypeInteger.js +72 -0
- package/lib/simple/XSSimpleTypeQName.js +24 -0
- package/lib/validation/Match.js +54 -0
- package/lib/validation/MatchAll.js +33 -0
- package/lib/validation/MatchAny.js +15 -0
- package/lib/validation/MatchChoice.js +74 -0
- package/lib/validation/MatchElement.js +45 -0
- package/lib/validation/MatchSequence.js +84 -0
- package/lib/validation/Occurable.js +88 -0
- package/lib/validation/XMLValidationState.js +169 -0
- package/lib/validation/XMLValidatior.js +38 -0
- package/lib/xml.xsd +1 -1
- package/package.json +1 -1
- package/lib/XSSimpleType.js +0 -329
package/README.md
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|

|
|
2
2
|

|
|
3
|
+
[](https://deepwiki.com/do-/node-xml-toolkit)
|
|
3
4
|
|
|
4
5
|
`node-xml-toolkit` is a pure node.js library for solving diverse XML related application tasks, e. g.:
|
|
5
6
|
* scanning through multi gigabyte long XML files with a limited memory buffer;
|
|
@@ -13,16 +14,19 @@ It features both (fast and simple, but greedy) [synchronous](https://github.com/
|
|
|
13
14
|
npm install xml-toolkit
|
|
14
15
|
```
|
|
15
16
|
|
|
16
|
-
#
|
|
17
|
-
|
|
18
|
-
* [Parsing a small file completely](XMLParser)
|
|
17
|
+
# Usage
|
|
18
|
+
* [Parsing a small file completely](XMLParser) (optionally validating)
|
|
19
19
|
|
|
20
20
|
```js
|
|
21
21
|
const fs = require ('fs')
|
|
22
|
-
const {XMLParser} = require ('xml-toolkit')
|
|
22
|
+
const {XMLParser, XMLSchemata} = require ('xml-toolkit')
|
|
23
23
|
|
|
24
24
|
const xml = fs.readFileSync ('doc.xml')
|
|
25
|
-
const
|
|
25
|
+
// const xs = new XMLSchemata ('schema.xsd')
|
|
26
|
+
|
|
27
|
+
const parser = new XMLParser ({
|
|
28
|
+
// xs,
|
|
29
|
+
})
|
|
26
30
|
|
|
27
31
|
const document = parser.process (xml)
|
|
28
32
|
|
|
@@ -31,12 +35,15 @@ for (const element of document.detach ().children) {
|
|
|
31
35
|
}
|
|
32
36
|
```
|
|
33
37
|
|
|
34
|
-
* [Reading a Record List](https://github.com/do-/node-xml-toolkit/wiki/Use-Case:-Reading-a-Record-List)
|
|
38
|
+
* [Reading a Record List](https://github.com/do-/node-xml-toolkit/wiki/Use-Case:-Reading-a-Record-List) (optionally validating)
|
|
35
39
|
|
|
36
40
|
```js
|
|
37
|
-
const {XMLReader, XMLNode} = require ('xml-toolkit')
|
|
41
|
+
const {XMLReader, XMLNode, XMLSchemata} = require ('xml-toolkit')
|
|
42
|
+
|
|
43
|
+
// const xs = new XMLSchemata ('schema.xsd')
|
|
38
44
|
|
|
39
45
|
const records = new XMLReader ({
|
|
46
|
+
//xs,
|
|
40
47
|
filterElements : 'Record',
|
|
41
48
|
map : XMLNode.toObject ({})
|
|
42
49
|
}).process (xmlSource)
|
|
@@ -56,7 +63,7 @@ const records = new XMLReader ({
|
|
|
56
63
|
// records.on ('data', record => doSomethingWith (record))
|
|
57
64
|
```
|
|
58
65
|
|
|
59
|
-
* [Getting a Single Element](https://github.com/do-/node-xml-toolkit/wiki/Use-Case:-Getting-a-Single-Element)
|
|
66
|
+
* [Getting a Single Element](https://github.com/do-/node-xml-toolkit/wiki/Use-Case:-Getting-a-Single-Element)
|
|
60
67
|
|
|
61
68
|
```js
|
|
62
69
|
const {XMLReader, XMLNode} = require ('xml-toolkit')
|
|
@@ -67,6 +74,21 @@ const data = await new XMLReader ({
|
|
|
67
74
|
}).process (xmlSource).findFirst ()
|
|
68
75
|
```
|
|
69
76
|
|
|
77
|
+
* [Formatting XML](https://github.com/do-/node-xml-toolkit/wiki/XMLPrinter)
|
|
78
|
+
```js
|
|
79
|
+
const {XMLParser} = require ('xml-toolkit')
|
|
80
|
+
xml = new XMLParser ()
|
|
81
|
+
.process (fs.readFileSync ('doc.xml'))
|
|
82
|
+
.toString ({
|
|
83
|
+
// decl: {encoding: 'UTF-8', standalone: 1},
|
|
84
|
+
space: '\t',
|
|
85
|
+
// attrSpace: 2,
|
|
86
|
+
// EOL: '\n',
|
|
87
|
+
// level: 0,
|
|
88
|
+
// encodeLineBreaks: false,
|
|
89
|
+
})
|
|
90
|
+
```
|
|
91
|
+
|
|
70
92
|
* [Patching XML](https://github.com/do-/node-xml-toolkit/wiki/Use-Case:-Patching-XML)
|
|
71
93
|
|
|
72
94
|
```js
|
|
@@ -80,8 +102,6 @@ let xmlResult = ''; for await (const node of new XMLReader ().process (xmlSource
|
|
|
80
102
|
* [Serializing an Object According to an XML Schema](https://github.com/do-/node-xml-toolkit/wiki/Use-Case:-Serializing-an-Object-According-to-an-XML-Schema)
|
|
81
103
|
|
|
82
104
|
```js
|
|
83
|
-
const {XMLSchemata} = require ('xml-toolkit')
|
|
84
|
-
|
|
85
105
|
const data = {ExportDebtRequestsResponse: {
|
|
86
106
|
"request-data": {
|
|
87
107
|
// ...
|
|
@@ -98,14 +118,13 @@ const xml = xs.stringify (data)
|
|
|
98
118
|
<!-- ... and so on ... -->
|
|
99
119
|
*/
|
|
100
120
|
```
|
|
101
|
-
|
|
102
|
-
* Invoking a [SOAP 1.1](https://github.com/do-/node-xml-toolkit/wiki/SOAP11) or [SOAP 1.2](https://github.com/do-/node-xml-toolkit/wiki/SOAP12) Web Service
|
|
121
|
+
* Invoking a [SOAP 1.1](SOAP11) Web Service
|
|
103
122
|
|
|
104
123
|
```js
|
|
105
124
|
const http = require ('http')
|
|
106
|
-
const {SOAP11
|
|
125
|
+
const {SOAP11} = require ('xml-toolkit')
|
|
107
126
|
|
|
108
|
-
const soap = new SOAP11 ('their.wsdl')
|
|
127
|
+
const soap = new SOAP11 ('their.wsdl')
|
|
109
128
|
|
|
110
129
|
const {method, headers, body} = soap.http ({RequestElementNameOfTheirs: {amount: '0.01'}})
|
|
111
130
|
|
|
@@ -113,32 +132,6 @@ const rq = http.request (endpointURL, {method, headers})
|
|
|
113
132
|
rq.write (body)
|
|
114
133
|
```
|
|
115
134
|
|
|
116
|
-
* [Implementing](https://github.com/do-/node-xml-toolkit/wiki/Use-Case:-Implement-a-SOAP-Web-Service) a SOAP service
|
|
117
|
-
|
|
118
|
-
```js
|
|
119
|
-
const {XMLSchemata, SOAP11, SOAP12, SOAPFault} = require ('xml-toolkit')
|
|
120
|
-
|
|
121
|
-
const SOAP = SOAP11 // or SOAP12
|
|
122
|
-
|
|
123
|
-
const xs = new XMLSchemata (`myService.wsdl`)
|
|
124
|
-
|
|
125
|
-
let body, statusCode; try {
|
|
126
|
-
body = xs.stringify (myMethod (/*...*/))
|
|
127
|
-
statusCode = 200
|
|
128
|
-
}
|
|
129
|
-
catch (x) {
|
|
130
|
-
body = new SOAPFault (x)
|
|
131
|
-
statusCode = 500
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
rp.writeHead (statusCode, {
|
|
135
|
-
'Content-Type': SOAP.contentType,
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
const xml = SOAP.message (body)
|
|
139
|
-
rp.end (xml)
|
|
140
|
-
```
|
|
141
|
-
|
|
142
135
|
# Motivation
|
|
143
136
|
|
|
144
137
|
Unlike Java (with [JAXB](https://www.oracle.com/technical-resources/articles/javase/jaxb.html) and [JAX-WS](https://www.oracle.com/technical-resources/articles/javase/jax-ws-2.html)) and some other software development platforms dating back to late 1990s, the core node.js library doesn't offer any standard tool for dealing with XML.
|
|
@@ -154,9 +147,6 @@ Pure js 3rd party modules are abundant, but after some real tasks based research
|
|
|
154
147
|
|
|
155
148
|
No W3C specification is 100% implemented here. For instance, DTDs are not supported, so, in theory, any rogue XML file using such bizarre deprecated feature as [Entity Declarations](https://www.w3.org/TR/xml/#sec-entity-decl) may crash the local XML parser.
|
|
156
149
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
In short, `node-xml-toolkit` may produce incorrect results for some input data, especially for deliberately broken ones.
|
|
150
|
+
The [XMLSchema](https://github.com/do-/node-xml-toolkit/wiki/XMLSchemata) is fairly usable for most real world cases, still some features (like `xs:unique`) are ignored completely, some others may require more test coverage. In general, XML Schema support in `xml-toolkit` should be considered _forever beta_.
|
|
160
151
|
|
|
161
|
-
There are perfectly reliable external tools for XML validation: for instance,
|
|
162
|
-
[xmllint](https://linux.die.net/man/1/xmllint) (used in the test suite here) do just fine.
|
|
152
|
+
There are perfectly reliable external tools for XML validation: for instance, [xmllint](https://linux.die.net/man/1/xmllint) (used in the test suite here) do just fine.
|
package/index.js
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
const {
|
|
2
2
|
XSSimpleType,
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
} = require ('./lib/simple/XSSimpleType')
|
|
4
|
+
|
|
5
|
+
const {
|
|
5
6
|
XSSimpleTypeDate,
|
|
6
7
|
XSSimpleTypeDateTime,
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
} = require ('./lib/simple/XSSimpleTypeDT')
|
|
9
|
+
|
|
10
|
+
const {
|
|
11
|
+
XSSimpleTypeFloat,
|
|
12
|
+
XSSimpleTypeDouble,
|
|
13
|
+
} = require ('./lib/simple/XSSimpleTypeFloatingPoint')
|
|
9
14
|
|
|
10
15
|
module.exports = {
|
|
11
16
|
AttributesMap: require ('./lib/AttributesMap'),
|
|
@@ -20,17 +25,19 @@ module.exports = {
|
|
|
20
25
|
XMLNode: require ('./lib/XMLNode'),
|
|
21
26
|
XMLLexer: require ('./lib/XMLLexer'),
|
|
22
27
|
XMLParser: require ('./lib/XMLParser'),
|
|
23
|
-
XMLPrinter: require ('./lib/XMLPrinter'),
|
|
28
|
+
XMLPrinter: require ('./lib/printer/XMLPrinter'),
|
|
29
|
+
XMLStreamPrinter: require ('./lib/printer/XMLStreamPrinter'),
|
|
24
30
|
XMLReader: require ('./lib/XMLReader'),
|
|
25
31
|
XMLSchema: require ('./lib/XMLSchema'),
|
|
26
32
|
XMLSchemaBuiltIn: require ('./lib/XMLSchemaBuiltIn'),
|
|
27
33
|
XMLSchemata: require ('./lib/XMLSchemata'),
|
|
28
34
|
XSSimpleType,
|
|
29
35
|
XSSimpleTypeFloat,
|
|
30
|
-
|
|
36
|
+
XSSimpleTypeDouble,
|
|
37
|
+
XSSimpleTypeBoolean: require ('./lib/simple/XSSimpleTypeBoolean'),
|
|
31
38
|
XSSimpleTypeDate,
|
|
32
39
|
XSSimpleTypeDateTime,
|
|
33
|
-
XSSimpleTypeQName,
|
|
40
|
+
XSSimpleTypeQName: require ('./lib/simple/XSSimpleTypeQName'),
|
|
34
41
|
}
|
|
35
42
|
|
|
36
43
|
module.exports.SOAP = v => {switch (String (v)) {
|
package/lib/XMLMarshaller.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
const assert = require ('assert')
|
|
2
2
|
const NamespacePrefixesMap = require ('./NamespacePrefixesMap.js')
|
|
3
|
-
const XMLPrinter = require ('./XMLPrinter.js')
|
|
3
|
+
const XMLPrinter = require ('./printer/XMLPrinter.js')
|
|
4
|
+
const XMLStreamPrinter = require ('./printer/XMLStreamPrinter.js')
|
|
5
|
+
const {Readable} = require ('node:stream')
|
|
4
6
|
|
|
5
7
|
const XSI_TYPE = Symbol.for ('type')
|
|
6
8
|
|
|
@@ -15,10 +17,10 @@ const XMLMarshaller = class {
|
|
|
15
17
|
this.schemaElement = this.schema.get (localName); assert (this.schemaElement, 'No schema element found for namespaceURI = ' + namespaceURI + ', localName = ' + localName)
|
|
16
18
|
|
|
17
19
|
this.ns = new NamespacePrefixesMap (xs)
|
|
18
|
-
|
|
20
|
+
|
|
19
21
|
this.isNsDumped = false
|
|
20
|
-
|
|
21
|
-
this.printer = new XMLPrinter (printerOptions)
|
|
22
|
+
|
|
23
|
+
this.printer = new ('out' in printerOptions ? XMLStreamPrinter : XMLPrinter) (printerOptions)
|
|
22
24
|
|
|
23
25
|
}
|
|
24
26
|
|
|
@@ -40,28 +42,39 @@ const XMLMarshaller = class {
|
|
|
40
42
|
|
|
41
43
|
try {
|
|
42
44
|
|
|
43
|
-
this.appendElement (schemaElement, data, this.ns.QName (o.localName || attributes.name, targetNamespace))
|
|
45
|
+
const result = this.appendElement (schemaElement, data, this.ns.QName (o.localName || attributes.name, targetNamespace))
|
|
46
|
+
|
|
47
|
+
if (result instanceof Promise) {
|
|
48
|
+
|
|
49
|
+
result.then (printer.end, printer.destroy)
|
|
50
|
+
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
|
|
54
|
+
return printer.text
|
|
55
|
+
|
|
56
|
+
}
|
|
44
57
|
|
|
45
58
|
}
|
|
46
59
|
catch (cause) {
|
|
47
60
|
|
|
48
61
|
const {targetNamespace, attributes: {name}} = schemaElement
|
|
49
62
|
|
|
50
|
-
throw Error (`Cannot stringify ${JSON.stringify (data)} as ${name}#{${targetNamespace}}`, {cause})
|
|
63
|
+
throw Error (`Cannot stringify ${JSON.stringify (data)} as ${name}#{${targetNamespace}}: ${cause.message}`, {cause})
|
|
51
64
|
|
|
52
65
|
}
|
|
53
66
|
|
|
54
|
-
return printer.text
|
|
55
|
-
|
|
56
67
|
}
|
|
57
68
|
|
|
58
69
|
appendElement (node, data, qName) {
|
|
59
70
|
|
|
60
71
|
this.appendStartTag (node, data, qName)
|
|
61
|
-
|
|
62
|
-
this.appendElementBody (node, data)
|
|
63
|
-
|
|
64
|
-
|
|
72
|
+
|
|
73
|
+
const result = this.appendElementBody (node, data), finish = () => this.printer.closeElement ()
|
|
74
|
+
|
|
75
|
+
if (!(result instanceof Promise)) return finish ()
|
|
76
|
+
|
|
77
|
+
return result.then (finish, this.printer.destroy)
|
|
65
78
|
|
|
66
79
|
}
|
|
67
80
|
|
|
@@ -71,7 +84,7 @@ const XMLMarshaller = class {
|
|
|
71
84
|
|
|
72
85
|
if (!this.isNsDumped) {
|
|
73
86
|
|
|
74
|
-
this.printer.
|
|
87
|
+
this.printer.write (this.ns.toString ())
|
|
75
88
|
|
|
76
89
|
this.isNsDumped = true
|
|
77
90
|
|
|
@@ -110,13 +123,19 @@ const XMLMarshaller = class {
|
|
|
110
123
|
const {attributes: {type}, children} = node
|
|
111
124
|
|
|
112
125
|
if (data && data [XSI_TYPE]) {
|
|
113
|
-
|
|
114
|
-
|
|
126
|
+
|
|
127
|
+
const d = {}; for (let k in data) d [k] = data [k]
|
|
128
|
+
|
|
129
|
+
return this.appendContent (this.schema.getType (data [XSI_TYPE]), d)
|
|
130
|
+
|
|
115
131
|
}
|
|
132
|
+
else if (type) {
|
|
116
133
|
|
|
117
|
-
|
|
134
|
+
return this.appendContent (this.xs.getType (type), data)
|
|
118
135
|
|
|
119
|
-
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return this.appendAllContent (children, data)
|
|
120
139
|
|
|
121
140
|
}
|
|
122
141
|
|
|
@@ -142,7 +161,7 @@ const XMLMarshaller = class {
|
|
|
142
161
|
|
|
143
162
|
return this.printer.writeAttribute (
|
|
144
163
|
this.ns.QName (name, targetNamespace),
|
|
145
|
-
this.xs.getAttributeSimpleType (node).stringify (v)
|
|
164
|
+
this.xs.getAttributeSimpleType (node).stringify (v) // throws
|
|
146
165
|
)
|
|
147
166
|
|
|
148
167
|
case 'extension':
|
|
@@ -178,7 +197,7 @@ const XMLMarshaller = class {
|
|
|
178
197
|
|
|
179
198
|
const type = this.xs.getSimpleType (node)
|
|
180
199
|
|
|
181
|
-
const xml = type.stringify (data)
|
|
200
|
+
const xml = type.stringify (data) // throws
|
|
182
201
|
|
|
183
202
|
this.printer.writeCharacters (xml)
|
|
184
203
|
|
|
@@ -192,6 +211,8 @@ const XMLMarshaller = class {
|
|
|
192
211
|
|
|
193
212
|
const qName = this.ns.QName (name, targetNamespace)
|
|
194
213
|
|
|
214
|
+
if (v instanceof Readable) return this.printer.forEach (v, d => this.appendElement (node, d, qName))
|
|
215
|
+
|
|
195
216
|
if (!Array.isArray (v)) return this.appendElement (node, v, qName)
|
|
196
217
|
|
|
197
218
|
for (const d of v) this.appendElement (node, d, qName)
|
|
@@ -199,17 +220,29 @@ const XMLMarshaller = class {
|
|
|
199
220
|
return
|
|
200
221
|
|
|
201
222
|
case 'extension':
|
|
202
|
-
|
|
203
|
-
this.
|
|
204
|
-
|
|
223
|
+
|
|
224
|
+
return this.appendAllContent ([this.xs.getType (attributes.base), ...children], data)
|
|
225
|
+
|
|
205
226
|
default:
|
|
206
227
|
|
|
207
|
-
|
|
228
|
+
return this.appendAllContent (children, data)
|
|
208
229
|
|
|
209
230
|
}
|
|
210
231
|
|
|
211
232
|
}
|
|
212
|
-
|
|
233
|
+
|
|
234
|
+
appendAllContent (list, data) {
|
|
235
|
+
|
|
236
|
+
for (let i = 0; i < list.length; i ++) {
|
|
237
|
+
|
|
238
|
+
const result = this.appendContent (list [i], data); if (!(result instanceof Promise)) continue
|
|
239
|
+
|
|
240
|
+
return result.then (this.appendAllContent (list.slice (i + 1), data), this.printer.destroy)
|
|
241
|
+
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
}
|
|
245
|
+
|
|
213
246
|
}
|
|
214
247
|
|
|
215
248
|
module.exports = XMLMarshaller
|
package/lib/XMLNode.js
CHANGED
package/lib/XMLParser.js
CHANGED
|
@@ -1,21 +1,40 @@
|
|
|
1
|
-
const
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
const
|
|
1
|
+
const SAXEvent = require ('./SAXEvent.js')
|
|
2
|
+
const XMLNode = require ('./XMLNode.js')
|
|
3
|
+
const XMLIterator = require ('./XMLIterator.js')
|
|
4
|
+
const XMLValidatior = require ('./validation/XMLValidatior.js')
|
|
5
5
|
|
|
6
6
|
const XMLParser = class {
|
|
7
7
|
|
|
8
8
|
constructor (options = {}) {
|
|
9
|
-
|
|
10
|
-
if (!('stripSpace' in options)) options.stripSpace = true
|
|
11
|
-
assert (options.stripSpace === true || options.stripSpace === false, 'options.stripSpace must be boolean, not ' + typeof options.stripSpace)
|
|
12
9
|
|
|
13
|
-
if (
|
|
14
|
-
|
|
10
|
+
if ('xs' in options) {
|
|
11
|
+
|
|
12
|
+
const {xs} = options; if (!(xs instanceof Map && xs.constructor.name === 'XMLSchemata')) throw Error (`options.xs must be an XMLSchemata instance, found ${typeof xs} '${xs}'`)
|
|
13
|
+
|
|
14
|
+
this.xs = xs
|
|
15
|
+
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
|
|
19
|
+
this.xs = null
|
|
20
|
+
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
for (const k of ['stripSpace', 'useEntities', 'useNamespaces']) {
|
|
24
|
+
|
|
25
|
+
if (!(k in options)) options [k] = true
|
|
15
26
|
|
|
16
|
-
|
|
17
|
-
|
|
27
|
+
switch (options [k]) {
|
|
28
|
+
case false:
|
|
29
|
+
if (this.xs !== null && k === 'useNamespaces') throw Error (`With an XMLSchema provided, options.${k} cannot be false`)
|
|
30
|
+
case true:
|
|
31
|
+
break
|
|
32
|
+
default:
|
|
33
|
+
throw Error (`options.${k} must be boolean, found ${typeof options [k]} '${options [k]}'`)
|
|
34
|
+
}
|
|
18
35
|
|
|
36
|
+
}
|
|
37
|
+
|
|
19
38
|
this.stripSpace = options.stripSpace
|
|
20
39
|
this.useEntities = options.useEntities
|
|
21
40
|
this.useNamespaces = options.useNamespaces
|
|
@@ -46,9 +65,11 @@ const XMLParser = class {
|
|
|
46
65
|
|
|
47
66
|
default:
|
|
48
67
|
|
|
49
|
-
if (this.text.length === 0) break
|
|
50
68
|
if (this.stripSpace) this.text = this.text.trim ()
|
|
51
69
|
if (this.text.length === 0) break
|
|
70
|
+
if (this.validator) {
|
|
71
|
+
this.validator.characters (this.text)
|
|
72
|
+
}
|
|
52
73
|
(new XMLNode (this.text, null, SAXEvent.TYPES.CHARACTERS)).parent = this.element
|
|
53
74
|
this.text = ''
|
|
54
75
|
|
|
@@ -61,14 +82,22 @@ const XMLParser = class {
|
|
|
61
82
|
node.parent = this.element
|
|
62
83
|
if (this.useNamespaces) node.readNamespaces ()
|
|
63
84
|
this.element = node
|
|
64
|
-
if (this.document === null)
|
|
85
|
+
if (this.document === null) {
|
|
86
|
+
this.document = node
|
|
87
|
+
if (this.xs !== null) this.validator = new XMLValidatior (this.xs, node, () => nodes.pos)
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
if (this.xs !== null) this.validator.startElement (node)
|
|
91
|
+
}
|
|
65
92
|
break
|
|
66
93
|
|
|
67
94
|
case SAXEvent.TYPES.END_ELEMENT:
|
|
68
95
|
|
|
69
96
|
if (this.element === null) throw new Error (`Unbalanced end element tag "${node.text}" occured at position ${nodes.pos}`)
|
|
97
|
+
node ['_ns_map'] = this.element ['_ns_map']
|
|
70
98
|
this.element.type = type
|
|
71
99
|
this.element = this.element.parent
|
|
100
|
+
if (this.xs !== null) this.validator.endElement (node)
|
|
72
101
|
break
|
|
73
102
|
|
|
74
103
|
}
|
package/lib/XMLReader.js
CHANGED
|
@@ -3,6 +3,7 @@ const {Transform} = require ('stream')
|
|
|
3
3
|
const SAXEvent = require ('./SAXEvent.js')
|
|
4
4
|
const XMLNode = require ('./XMLNode.js')
|
|
5
5
|
const XMLLexer = require ('./XMLLexer.js')
|
|
6
|
+
const XMLValidatior = require ('./validation/XMLValidatior.js')
|
|
6
7
|
|
|
7
8
|
const OPT_SRC = Symbol ('_src')
|
|
8
9
|
const OPT_SAX = Symbol ('_sax')
|
|
@@ -54,6 +55,14 @@ const XMLReader = class extends Transform {
|
|
|
54
55
|
|
|
55
56
|
super (options)
|
|
56
57
|
|
|
58
|
+
if ('xs' in options) {
|
|
59
|
+
this.xs = options.xs
|
|
60
|
+
this.validator = null
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
this.xs = null
|
|
64
|
+
}
|
|
65
|
+
|
|
57
66
|
this.stripSpace = options.stripSpace
|
|
58
67
|
this.useEntities = options.useEntities
|
|
59
68
|
this.useNamespaces = options.useNamespaces
|
|
@@ -133,11 +142,46 @@ const XMLReader = class extends Transform {
|
|
|
133
142
|
return this [OPT_SAX] = false
|
|
134
143
|
|
|
135
144
|
}
|
|
145
|
+
|
|
146
|
+
validate (xmlNode) {
|
|
147
|
+
|
|
148
|
+
if (!this.validator) switch (xmlNode.type) {
|
|
149
|
+
|
|
150
|
+
case SAXEvent.TYPES.START_ELEMENT:
|
|
151
|
+
this.validator = new XMLValidatior (this.xs, xmlNode, () => this.position)
|
|
152
|
+
|
|
153
|
+
default:
|
|
154
|
+
return
|
|
155
|
+
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
switch (xmlNode.type) {
|
|
159
|
+
|
|
160
|
+
case SAXEvent.TYPES.START_ELEMENT : return this.validator.startElement (xmlNode)
|
|
161
|
+
|
|
162
|
+
case SAXEvent.TYPES.CHARACTERS : return this.validator.characters (xmlNode.src)
|
|
163
|
+
|
|
164
|
+
case SAXEvent.TYPES.END_ELEMENT : return this.validator.endElement (xmlNode)
|
|
165
|
+
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
}
|
|
136
169
|
|
|
137
170
|
publish (xmlNode, type = null) {
|
|
138
171
|
|
|
139
172
|
if (type !== null) xmlNode.type = type
|
|
140
173
|
|
|
174
|
+
if (this.xs) try {
|
|
175
|
+
|
|
176
|
+
this.validate (xmlNode)
|
|
177
|
+
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
|
|
181
|
+
this.destroy (error)
|
|
182
|
+
|
|
183
|
+
}
|
|
184
|
+
|
|
141
185
|
const {filter} = this; if (filter !== null) {
|
|
142
186
|
|
|
143
187
|
if (!filter (xmlNode)) return
|
package/lib/XMLSchema.js
CHANGED
|
@@ -70,6 +70,16 @@ const XMLSchema = class extends Map {
|
|
|
70
70
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
getElement (localName) {
|
|
74
|
+
|
|
75
|
+
const el = this.get (localName)
|
|
76
|
+
|
|
77
|
+
if (!el || el.localName !== 'element') throw Error (`The element ${localName} is not found in ${this.targetNamespace}`)
|
|
78
|
+
|
|
79
|
+
return el
|
|
80
|
+
|
|
81
|
+
}
|
|
82
|
+
|
|
73
83
|
setSource (node) {
|
|
74
84
|
|
|
75
85
|
this.defaultNamespace = node.namespacesMap.default
|
|
@@ -94,6 +104,7 @@ const XMLSchema = class extends Map {
|
|
|
94
104
|
this [TYPES].set (name, e)
|
|
95
105
|
break
|
|
96
106
|
default:
|
|
107
|
+
// console.log ([name, localName, this.targetNamespace])
|
|
97
108
|
this.set (name, e)
|
|
98
109
|
}
|
|
99
110
|
|
package/lib/XMLSchemaBuiltIn.js
CHANGED
|
@@ -2,7 +2,13 @@ const fs = require ('fs')
|
|
|
2
2
|
const path = require ('path')
|
|
3
3
|
|
|
4
4
|
const XMLSchema = require ('./XMLSchema.js')
|
|
5
|
-
const {XSSimpleType} = require ('./XSSimpleType.js')
|
|
5
|
+
const {XSSimpleType} = require ('./simple/XSSimpleType.js')
|
|
6
|
+
const XSSimpleTypeDT = require ('./simple/XSSimpleTypeDT.js')
|
|
7
|
+
const XSSimpleTypeDecimal = require ('./simple/XSSimpleTypeDecimal.js')
|
|
8
|
+
const XSSimpleTypeInteger = require ('./simple/XSSimpleTypeInteger.js')
|
|
9
|
+
const XSSimpleTypeBoolean = require ('./simple/XSSimpleTypeBoolean.js')
|
|
10
|
+
const XSSimpleTypeFloatingPoint = require ('./simple/XSSimpleTypeFloatingPoint.js')
|
|
11
|
+
const XSSimpleTypeQName = require ('./simple/XSSimpleTypeQName.js')
|
|
6
12
|
|
|
7
13
|
class XMLSchemaBuiltIn extends XMLSchema {
|
|
8
14
|
|
|
@@ -14,15 +20,24 @@ class XMLSchemaBuiltIn extends XMLSchema {
|
|
|
14
20
|
|
|
15
21
|
const doc = parent.parser.process (xml)
|
|
16
22
|
|
|
17
|
-
super (parent, XMLSchema.namespaceURI, doc)
|
|
23
|
+
super (parent, XMLSchema.namespaceURI, doc)
|
|
24
|
+
|
|
25
|
+
this.byName = {
|
|
26
|
+
...XSSimpleTypeInteger.byName,
|
|
27
|
+
...XSSimpleTypeFloatingPoint.byName,
|
|
28
|
+
...XSSimpleTypeDT.byName,
|
|
29
|
+
QName : XSSimpleTypeQName,
|
|
30
|
+
boolean : XSSimpleTypeBoolean,
|
|
31
|
+
decimal : XSSimpleTypeDecimal,
|
|
32
|
+
}
|
|
18
33
|
|
|
19
34
|
}
|
|
20
35
|
|
|
21
|
-
getSimpleTypeClass (
|
|
36
|
+
getSimpleTypeClass ({attributes: {name}}) {
|
|
22
37
|
|
|
23
|
-
return
|
|
38
|
+
return this.byName [name] ?? XSSimpleType
|
|
24
39
|
|
|
25
|
-
}
|
|
40
|
+
}
|
|
26
41
|
|
|
27
42
|
}
|
|
28
43
|
|