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/lib/XMLSchemata.js
CHANGED
|
@@ -8,7 +8,8 @@ const XMLSchemaXml = require ('./XMLSchemaXml.js')
|
|
|
8
8
|
const XMLSchemaBuiltIn = require ('./XMLSchemaBuiltIn.js')
|
|
9
9
|
const XMLMarshaller = require ('./XMLMarshaller.js')
|
|
10
10
|
|
|
11
|
-
const
|
|
11
|
+
const XSAnyType = require ('./XSAnyType.js')
|
|
12
|
+
const {XSSimpleType} = require ('./simple/XSSimpleType.js')
|
|
12
13
|
|
|
13
14
|
const IDX = Symbol ('_index')
|
|
14
15
|
|
|
@@ -32,6 +33,12 @@ const XMLSchemata = class extends Map {
|
|
|
32
33
|
this.addFile (fn)
|
|
33
34
|
|
|
34
35
|
}
|
|
36
|
+
|
|
37
|
+
getDebugQName (localName, namespaceURI) {
|
|
38
|
+
|
|
39
|
+
return namespaceURI ? `{${namespaceURI}}${localName}` : localName
|
|
40
|
+
|
|
41
|
+
}
|
|
35
42
|
|
|
36
43
|
register (name, targetNamespace) {
|
|
37
44
|
|
|
@@ -51,10 +58,20 @@ const XMLSchemata = class extends Map {
|
|
|
51
58
|
|
|
52
59
|
if (node.localName === 'simpleType' && !node._xsSimpleType) node._xsSimpleType = new (schema.getSimpleTypeClass (node)) (this)
|
|
53
60
|
|
|
61
|
+
if (!('targetNamespace' in node)) node.targetNamespace = namespaceURI
|
|
62
|
+
|
|
54
63
|
return node
|
|
55
64
|
|
|
56
65
|
}
|
|
57
66
|
|
|
67
|
+
getAnyType (node) {
|
|
68
|
+
|
|
69
|
+
if ('_xsAnyType' in node) return node._xsAnyType
|
|
70
|
+
|
|
71
|
+
return node._xsAnyType = new XSAnyType (this, node)
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
|
|
58
75
|
getSimpleType (node) {
|
|
59
76
|
|
|
60
77
|
if ('_xsSimpleType' in node) return node._xsSimpleType
|
|
@@ -65,15 +82,65 @@ const XMLSchemata = class extends Map {
|
|
|
65
82
|
|
|
66
83
|
getSimpleTypeClass (node) {
|
|
67
84
|
|
|
68
|
-
if (node) for (const {localName,
|
|
69
|
-
|
|
70
|
-
|
|
85
|
+
if (node) for (const {localName, attributes: {base}, children} of node.children) switch (localName) {
|
|
86
|
+
|
|
87
|
+
case 'restriction': return this.getType (base)._xsSimpleType.restrict (children)
|
|
88
|
+
|
|
89
|
+
case 'union': return class {
|
|
90
|
+
|
|
91
|
+
constructor (xs) {
|
|
92
|
+
|
|
93
|
+
this.xs = xs
|
|
94
|
+
|
|
95
|
+
this.nodes = children
|
|
96
|
+
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
stringify (v) {
|
|
100
|
+
|
|
101
|
+
const messages = []; for (const node of this.nodes) {
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
|
|
105
|
+
return this.xs.getSimpleType (node).stringify (v)
|
|
106
|
+
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
|
|
110
|
+
messages.push (err.message)
|
|
111
|
+
|
|
112
|
+
}
|
|
71
113
|
|
|
72
|
-
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
throw Error (messages.join ('; '))
|
|
73
117
|
|
|
74
|
-
|
|
118
|
+
}
|
|
75
119
|
|
|
76
|
-
)
|
|
120
|
+
validateScalar (v) {
|
|
121
|
+
|
|
122
|
+
const messages = []; for (const node of this.nodes) {
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
|
|
126
|
+
return this.xs.getSimpleType (node).validateScalar (v)
|
|
127
|
+
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
|
|
131
|
+
messages.push (err.message)
|
|
132
|
+
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
throw Error (messages.join ('; '))
|
|
138
|
+
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
}
|
|
77
144
|
|
|
78
145
|
return XSSimpleType
|
|
79
146
|
|
|
@@ -98,10 +165,26 @@ const XMLSchemata = class extends Map {
|
|
|
98
165
|
getByReference (ref) {
|
|
99
166
|
|
|
100
167
|
const [localName, namespaceURI] = ref
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
168
|
+
|
|
169
|
+
return this.getSchema (namespaceURI).get (localName)
|
|
170
|
+
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
getSchema (namespaceURI) {
|
|
174
|
+
|
|
175
|
+
if (!this.has (namespaceURI)) throw new Error ('Unknown namespace: ' + namespaceURI)
|
|
176
|
+
|
|
177
|
+
return this.get (namespaceURI)
|
|
178
|
+
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
getTypeDefinition (node) {
|
|
182
|
+
|
|
183
|
+
// while (node.attributes.ref) node = this.getByReference (node.attributes.ref)
|
|
184
|
+
|
|
185
|
+
if (node.attributes.type) return this.getType (node.attributes.type)
|
|
186
|
+
|
|
187
|
+
return node.children.find (i => i.localName.endsWith ('Type'))
|
|
105
188
|
|
|
106
189
|
}
|
|
107
190
|
|
package/lib/XSAnyType.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
const Occurable = require ('./validation/Occurable')
|
|
2
|
+
|
|
3
|
+
module.exports = class {
|
|
4
|
+
|
|
5
|
+
#isAnyAttributeAllowed = false
|
|
6
|
+
#isExtended = false
|
|
7
|
+
#parent = null
|
|
8
|
+
|
|
9
|
+
get isAnyAttributeAllowed () {
|
|
10
|
+
|
|
11
|
+
return this.#isAnyAttributeAllowed
|
|
12
|
+
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
constructor (xs, node) {
|
|
16
|
+
|
|
17
|
+
this.xs = xs
|
|
18
|
+
this.node = node
|
|
19
|
+
|
|
20
|
+
this.attributes = new Map ()
|
|
21
|
+
this.elements = []
|
|
22
|
+
|
|
23
|
+
this.scan (node)
|
|
24
|
+
|
|
25
|
+
if (this.#parent === null) return
|
|
26
|
+
|
|
27
|
+
if (this.#isExtended) this.extend (); else this.restrict ()
|
|
28
|
+
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
extend () {
|
|
32
|
+
|
|
33
|
+
this.attributes = new Map ([
|
|
34
|
+
...this.#parent.attributes,
|
|
35
|
+
...this.attributes
|
|
36
|
+
])
|
|
37
|
+
|
|
38
|
+
this.elements = this.#parent.elements.concat (this.elements)
|
|
39
|
+
|
|
40
|
+
this.content = new Occurable ([this.#parent.content, this.content])
|
|
41
|
+
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
restrict () {
|
|
45
|
+
|
|
46
|
+
this.attributes = new Map ([
|
|
47
|
+
...this.#parent.attributes,
|
|
48
|
+
...this.attributes
|
|
49
|
+
])
|
|
50
|
+
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
asSimpleType () {
|
|
54
|
+
|
|
55
|
+
return this.xs.getSimpleType (this.node)
|
|
56
|
+
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
get debugQName () {
|
|
60
|
+
|
|
61
|
+
const {xs, node} = this
|
|
62
|
+
|
|
63
|
+
return xs.getDebugQName (node.attributes.name, node.targetNamespace)
|
|
64
|
+
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
scan (node) {
|
|
68
|
+
|
|
69
|
+
while (node.attributes.ref) node = this.xs.getByReference (node.attributes.ref)
|
|
70
|
+
|
|
71
|
+
switch (node.localName) {
|
|
72
|
+
|
|
73
|
+
case 'anyAttribute': return this.#isAnyAttributeAllowed = true
|
|
74
|
+
|
|
75
|
+
case 'attribute': return this.attributes.set (node.attributes.name, node)
|
|
76
|
+
|
|
77
|
+
case 'any':
|
|
78
|
+
case 'element':
|
|
79
|
+
return this.elements.push (node)
|
|
80
|
+
|
|
81
|
+
case 'all':
|
|
82
|
+
case 'choice':
|
|
83
|
+
case 'sequence':
|
|
84
|
+
this.content ??= new Occurable (node, this.xs)
|
|
85
|
+
break
|
|
86
|
+
|
|
87
|
+
case 'extension':
|
|
88
|
+
this.#isExtended = true
|
|
89
|
+
case 'restriction':
|
|
90
|
+
this.#parent = this.xs.getAnyType (this.xs.getType (node.attributes.base))
|
|
91
|
+
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
for (const child of node.children) this.scan (child)
|
|
95
|
+
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const os = require ('os')
|
|
2
2
|
const stringEscape = require ('string-escape-map')
|
|
3
|
-
const SAXEvent = require ('
|
|
3
|
+
const SAXEvent = require ('../SAXEvent.js')
|
|
4
4
|
|
|
5
5
|
const CH_QQ = '"'.charCodeAt (0)
|
|
6
6
|
const CH_GT = '>'.charCodeAt (0)
|
|
@@ -19,7 +19,7 @@ const ESC = [
|
|
|
19
19
|
|
|
20
20
|
const isSafeNonNegative = value => Number.isSafeInteger (value) && value >= 0
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
module.exports = class {
|
|
23
23
|
|
|
24
24
|
constructor (o = {}) {
|
|
25
25
|
|
|
@@ -85,7 +85,6 @@ const XMLPrinter = class {
|
|
|
85
85
|
|
|
86
86
|
reset () {
|
|
87
87
|
|
|
88
|
-
this.text = ''
|
|
89
88
|
this.stack = []
|
|
90
89
|
this.isOpening = false
|
|
91
90
|
|
|
@@ -97,15 +96,7 @@ const XMLPrinter = class {
|
|
|
97
96
|
|
|
98
97
|
newLine (delta = 0) {
|
|
99
98
|
|
|
100
|
-
this.
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
get lastCharCode () {
|
|
105
|
-
|
|
106
|
-
const {text} = this
|
|
107
|
-
|
|
108
|
-
return text.charCodeAt (text.length - 1)
|
|
99
|
+
this.write (`${this.EOL}${this.space.repeat (this.level + this.stack.length + delta)}`)
|
|
109
100
|
|
|
110
101
|
}
|
|
111
102
|
|
|
@@ -113,12 +104,12 @@ const XMLPrinter = class {
|
|
|
113
104
|
|
|
114
105
|
if (this.stack.length !== 0) {
|
|
115
106
|
if (this.attrSpace && this.lastCharCode === CH_QQ) this.newLine (-1)
|
|
116
|
-
if (this.isOpening) this.
|
|
107
|
+
if (this.isOpening) this.write (`>`)
|
|
117
108
|
}
|
|
118
109
|
|
|
119
|
-
if (this.space && this.
|
|
110
|
+
if (this.space && !this.isVirgin) this.newLine ()
|
|
120
111
|
|
|
121
|
-
this.
|
|
112
|
+
this.write (`<${name}`)
|
|
122
113
|
this.stack.push (name)
|
|
123
114
|
|
|
124
115
|
this.isOpening = true
|
|
@@ -139,16 +130,16 @@ const XMLPrinter = class {
|
|
|
139
130
|
|
|
140
131
|
this.newLine (-1)
|
|
141
132
|
|
|
142
|
-
this.
|
|
133
|
+
this.write (this.attrSpace)
|
|
143
134
|
|
|
144
135
|
}
|
|
145
136
|
else {
|
|
146
137
|
|
|
147
|
-
this.
|
|
138
|
+
this.write (' ')
|
|
148
139
|
|
|
149
140
|
}
|
|
150
141
|
|
|
151
|
-
this.
|
|
142
|
+
this.write (`${name}="${this.ESC_ATTR.escape (value)}"`)
|
|
152
143
|
|
|
153
144
|
return this
|
|
154
145
|
|
|
@@ -170,11 +161,11 @@ const XMLPrinter = class {
|
|
|
170
161
|
|
|
171
162
|
if (this.isOpening) {
|
|
172
163
|
if (this.attrSpace && this.lastCharCode === CH_QQ) this.newLine (-1)
|
|
173
|
-
this.
|
|
164
|
+
this.write (`>`)
|
|
174
165
|
this.isOpening = false
|
|
175
166
|
}
|
|
176
167
|
|
|
177
|
-
this.
|
|
168
|
+
this.write (value)
|
|
178
169
|
|
|
179
170
|
return this
|
|
180
171
|
|
|
@@ -186,12 +177,12 @@ const XMLPrinter = class {
|
|
|
186
177
|
|
|
187
178
|
if (this.isOpening) {
|
|
188
179
|
if (this.attrSpace && this.lastCharCode === CH_QQ) this.newLine ()
|
|
189
|
-
this.
|
|
180
|
+
this.write (` />`)
|
|
190
181
|
this.isOpening = false
|
|
191
182
|
}
|
|
192
183
|
else {
|
|
193
184
|
if (this.space && this.lastCharCode === CH_GT) this.newLine ()
|
|
194
|
-
this.
|
|
185
|
+
this.write (`</${name}>`)
|
|
195
186
|
}
|
|
196
187
|
|
|
197
188
|
return this
|
|
@@ -271,18 +262,16 @@ const XMLPrinter = class {
|
|
|
271
262
|
|
|
272
263
|
if (this.stack.length !== 0) throw Error ('The document is already started')
|
|
273
264
|
|
|
274
|
-
this.
|
|
265
|
+
this.write ('<?xml version="1.0"')
|
|
275
266
|
|
|
276
|
-
if (encoding != null) this.
|
|
267
|
+
if (encoding != null) this.write (` encoding="${encoding}"`)
|
|
277
268
|
|
|
278
|
-
if (standalone != null) this.
|
|
269
|
+
if (standalone != null) this.write (` standalone="${standalone ? 'yes' : 'no'}"`)
|
|
279
270
|
|
|
280
|
-
this.
|
|
271
|
+
this.write ('?>')
|
|
281
272
|
|
|
282
273
|
return this
|
|
283
274
|
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
}
|
|
275
|
+
}
|
|
287
276
|
|
|
288
|
-
|
|
277
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const XMLPrinter = class extends (require ('./Base.js')) {
|
|
2
|
+
|
|
3
|
+
get destroy () {
|
|
4
|
+
|
|
5
|
+
return err => {throw err}
|
|
6
|
+
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
reset () {
|
|
10
|
+
|
|
11
|
+
this.text = ''
|
|
12
|
+
|
|
13
|
+
return super.reset ()
|
|
14
|
+
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
get lastCharCode () {
|
|
18
|
+
|
|
19
|
+
const {text} = this
|
|
20
|
+
|
|
21
|
+
return text.charCodeAt (text.length - 1)
|
|
22
|
+
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
get isVirgin () {
|
|
26
|
+
|
|
27
|
+
return this.text.length === 0
|
|
28
|
+
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
write (s) {
|
|
32
|
+
|
|
33
|
+
this.text += s
|
|
34
|
+
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = XMLPrinter
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
const {Writable} = require ('node:stream')
|
|
2
|
+
|
|
3
|
+
const XMLStreamPrinter = class extends (require ('./Base.js')) {
|
|
4
|
+
|
|
5
|
+
#inStreams = []
|
|
6
|
+
#isVirgin = true
|
|
7
|
+
#lastCharCode = 0
|
|
8
|
+
#open = true
|
|
9
|
+
|
|
10
|
+
constructor (o) {
|
|
11
|
+
|
|
12
|
+
if (!o || typeof o !== 'object' || !('out' in o)) throw Error (`XMLStreamPrinter requires an .out option`)
|
|
13
|
+
if (!(o.out instanceof Writable)) throw Error (`.out must be Writable, ${typeof o.out} ${o.out} found`)
|
|
14
|
+
|
|
15
|
+
super (o)
|
|
16
|
+
|
|
17
|
+
this.out = o.out
|
|
18
|
+
this.out.on ('drain', () => this.open = true)
|
|
19
|
+
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
get end () {
|
|
23
|
+
|
|
24
|
+
return () => this.out.end ()
|
|
25
|
+
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get destroy () {
|
|
29
|
+
|
|
30
|
+
return err => this.out.destroy (err)
|
|
31
|
+
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get inStream () {
|
|
35
|
+
|
|
36
|
+
return this.#inStreams.at (-1)
|
|
37
|
+
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
forEach (stream, onData) {
|
|
41
|
+
|
|
42
|
+
if (this.#inStreams.length !== 0) return this.destroy (Error ('Nested streams not yet supported'))
|
|
43
|
+
|
|
44
|
+
if (!this.#open) stream.pause ()
|
|
45
|
+
|
|
46
|
+
this.#inStreams.push (stream)
|
|
47
|
+
|
|
48
|
+
return new Promise ((ok, fail) => {
|
|
49
|
+
|
|
50
|
+
stream.on ('error', err => {
|
|
51
|
+
|
|
52
|
+
this.destroy (err)
|
|
53
|
+
|
|
54
|
+
fail (err)
|
|
55
|
+
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
stream.on ('end', () => {
|
|
59
|
+
|
|
60
|
+
this.#inStreams.pop ()
|
|
61
|
+
|
|
62
|
+
ok ()
|
|
63
|
+
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
stream.on ('data', data => {
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
|
|
70
|
+
onData (data)
|
|
71
|
+
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
|
|
75
|
+
stream.destroy (err)
|
|
76
|
+
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
set open (nowOpen) {
|
|
86
|
+
|
|
87
|
+
const wasOpen = this.#open; if (wasOpen === nowOpen) return
|
|
88
|
+
|
|
89
|
+
this.#open = nowOpen
|
|
90
|
+
|
|
91
|
+
if (!this.inStream) return
|
|
92
|
+
|
|
93
|
+
nowOpen ? this.inStream.resume () : this.inStream.pause ()
|
|
94
|
+
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
get lastCharCode () {
|
|
98
|
+
|
|
99
|
+
return this.#lastCharCode
|
|
100
|
+
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
get isVirgin () {
|
|
104
|
+
|
|
105
|
+
return this.#isVirgin
|
|
106
|
+
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
write (s) {
|
|
110
|
+
|
|
111
|
+
const {length} = s; if (length === 0) return
|
|
112
|
+
|
|
113
|
+
this.#lastCharCode = s.charCodeAt (length - 1)
|
|
114
|
+
this.#isVirgin = false
|
|
115
|
+
|
|
116
|
+
this.open = this.out.write (s)
|
|
117
|
+
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
module.exports = XMLStreamPrinter
|