xml-toolkit 1.0.39 → 1.0.41
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/index.js +17 -18
- package/lib/XMLNode.js +31 -6
- package/lib/XMLPrinter.js +280 -0
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -1,21 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
'
|
|
4
|
-
'
|
|
5
|
-
'
|
|
6
|
-
'
|
|
7
|
-
'
|
|
8
|
-
'
|
|
9
|
-
'
|
|
10
|
-
'
|
|
11
|
-
'
|
|
12
|
-
'
|
|
13
|
-
'
|
|
14
|
-
'
|
|
15
|
-
'
|
|
16
|
-
'
|
|
17
|
-
|
|
18
|
-
]) module.exports [name] = require ('./lib/' + name)
|
|
1
|
+
module.exports = {
|
|
2
|
+
AttributesMap: require ('./lib/AttributesMap'),
|
|
3
|
+
EntityResolver: require ('./lib/EntityResolver'),
|
|
4
|
+
MoxyLikeJsonEncoder: require ('./lib/MoxyLikeJsonEncoder'),
|
|
5
|
+
SOAP11: require ('./lib/SOAP11'),
|
|
6
|
+
SOAP12: require ('./lib/SOAP12'),
|
|
7
|
+
SOAPEncoding: require ('./lib/SOAPEncoding'),
|
|
8
|
+
SOAPFault: require ('./lib/SOAPFault'),
|
|
9
|
+
SAXEvent: require ('./lib/SAXEvent'),
|
|
10
|
+
XMLIterator: require ('./lib/XMLIterator'),
|
|
11
|
+
XMLNode: require ('./lib/XMLNode'),
|
|
12
|
+
XMLLexer: require ('./lib/XMLLexer'),
|
|
13
|
+
XMLParser: require ('./lib/XMLParser'),
|
|
14
|
+
XMLPrinter: require ('./lib/XMLPrinter'),
|
|
15
|
+
XMLReader: require ('./lib/XMLReader'),
|
|
16
|
+
XMLSchemata: require ('./lib/XMLSchemata'),
|
|
17
|
+
}
|
|
19
18
|
|
|
20
19
|
module.exports.SOAP = v => {switch (String (v)) {
|
|
21
20
|
|
package/lib/XMLNode.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
const os = require ('os')
|
|
1
2
|
const SAXEvent = require ('./SAXEvent.js')
|
|
3
|
+
const XMLPrinter = require ('./XMLPrinter.js')
|
|
2
4
|
const AttributesMap = require ('./AttributesMap')
|
|
3
5
|
const NamespacesMap = require ('./NamespacesMap')
|
|
4
6
|
const MoxyLikeJsonEncoder = require ('./MoxyLikeJsonEncoder')
|
|
@@ -10,6 +12,19 @@ const PARENT = Symbol ('_parent')
|
|
|
10
12
|
const LEVEL = Symbol ('_level')
|
|
11
13
|
const NS_MAP = Symbol ('_ns_map')
|
|
12
14
|
|
|
15
|
+
const stringEscape = require ('string-escape-map')
|
|
16
|
+
|
|
17
|
+
const ESC = [
|
|
18
|
+
['<', '<'],
|
|
19
|
+
['>', '>'],
|
|
20
|
+
['&', '&'],
|
|
21
|
+
[String.fromCharCode (10), '
'],
|
|
22
|
+
[String.fromCharCode (13), '
'],
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
const ESC_BODY = new stringEscape (ESC)
|
|
26
|
+
const ESC_ATTR = new stringEscape ([...ESC, ['"', '"']])
|
|
27
|
+
|
|
13
28
|
const m2o =
|
|
14
29
|
Object.fromEntries ? m => Object.fromEntries (m.entries ()) :
|
|
15
30
|
m => {let o = {}; for (const [k, v] of m.entries ()) o [k] = v; return o}
|
|
@@ -126,17 +141,27 @@ const XMLNode = class extends SAXEvent {
|
|
|
126
141
|
|
|
127
142
|
}
|
|
128
143
|
|
|
129
|
-
toString () {
|
|
144
|
+
toString (options, level = 0) {
|
|
130
145
|
|
|
131
|
-
|
|
146
|
+
if (arguments.length === 0) return this.toSourceString ()
|
|
132
147
|
|
|
133
|
-
|
|
148
|
+
const xp = new XMLPrinter ({level, ...options})
|
|
134
149
|
|
|
135
|
-
|
|
150
|
+
xp.writeNode (this)
|
|
136
151
|
|
|
137
|
-
|
|
152
|
+
return xp.text
|
|
138
153
|
|
|
139
|
-
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
toSourceString () {
|
|
157
|
+
|
|
158
|
+
const {src} = this; if (this.type !== SAXEvent.TYPES.END_ELEMENT || this.isSelfEnclosed) return src
|
|
159
|
+
|
|
160
|
+
let s = this.src
|
|
161
|
+
|
|
162
|
+
for (const child of this.children) s += child.toSourceString ()
|
|
163
|
+
|
|
164
|
+
return s + this.xml
|
|
140
165
|
|
|
141
166
|
}
|
|
142
167
|
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
const os = require ('os')
|
|
2
|
+
const stringEscape = require ('string-escape-map')
|
|
3
|
+
const SAXEvent = require ('./SAXEvent.js')
|
|
4
|
+
|
|
5
|
+
const CH_QQ = '"'.charCodeAt (0)
|
|
6
|
+
const CH_GT = '>'.charCodeAt (0)
|
|
7
|
+
|
|
8
|
+
const ESC = [
|
|
9
|
+
|
|
10
|
+
[ '"', '"'],
|
|
11
|
+
[ '<', '<'],
|
|
12
|
+
[ '>', '>'],
|
|
13
|
+
[ '&', '&'],
|
|
14
|
+
|
|
15
|
+
['\n', '
'],
|
|
16
|
+
['\r', '
'],
|
|
17
|
+
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
const isSafeNonNegative = value => Number.isSafeInteger (value) && value >= 0
|
|
21
|
+
|
|
22
|
+
const XMLPrinter = class {
|
|
23
|
+
|
|
24
|
+
constructor (o = {}) {
|
|
25
|
+
|
|
26
|
+
this.level = o.level ?? 0
|
|
27
|
+
|
|
28
|
+
if (!isSafeNonNegative (this.level)) throw Error ('Invalid level: ' + o.level)
|
|
29
|
+
|
|
30
|
+
const setSpaceOption = name => {
|
|
31
|
+
|
|
32
|
+
const value = o [name] || 0
|
|
33
|
+
|
|
34
|
+
this [name] = (() => {
|
|
35
|
+
|
|
36
|
+
switch (typeof value) {
|
|
37
|
+
|
|
38
|
+
case 'string': return value
|
|
39
|
+
|
|
40
|
+
case 'number': if (isSafeNonNegative (value)) return ' '.repeat (value)
|
|
41
|
+
|
|
42
|
+
default: throw Error (`Invalid ${name}: ${value}`)
|
|
43
|
+
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
}) ()
|
|
47
|
+
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
setSpaceOption ('space')
|
|
51
|
+
|
|
52
|
+
if (this.space) {
|
|
53
|
+
|
|
54
|
+
setSpaceOption ('attrSpace')
|
|
55
|
+
|
|
56
|
+
this.EOL = o.EOL ?? os.EOL
|
|
57
|
+
|
|
58
|
+
if (typeof this.EOL !== 'string') throw Error ('Invalid EOL: ' + o.EOL)
|
|
59
|
+
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
|
|
63
|
+
for (const name of ['attrSpace', 'EOL']) if (o [name] != null) throw Error (`Without .space, .${name} cannot be set`)
|
|
64
|
+
|
|
65
|
+
this.EOL = ''
|
|
66
|
+
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
this.encodeLineBreaks = o.encodeLineBreaks ?? true
|
|
70
|
+
|
|
71
|
+
{
|
|
72
|
+
|
|
73
|
+
const to = this.encodeLineBreaks ? Infinity : -2
|
|
74
|
+
|
|
75
|
+
this.ESC_BODY = new stringEscape (ESC.slice (1, to))
|
|
76
|
+
this.ESC_ATTR = new stringEscape (ESC.slice (0, to))
|
|
77
|
+
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
this.decl = o.decl
|
|
81
|
+
|
|
82
|
+
this.reset ()
|
|
83
|
+
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
reset () {
|
|
87
|
+
|
|
88
|
+
this.text = ''
|
|
89
|
+
this.stack = []
|
|
90
|
+
this.isOpening = false
|
|
91
|
+
|
|
92
|
+
const {decl} = this; if (decl) this.writeXMLDecl (decl)
|
|
93
|
+
|
|
94
|
+
return this
|
|
95
|
+
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
newLine (delta = 0) {
|
|
99
|
+
|
|
100
|
+
this.text += `${this.EOL}${this.space.repeat (this.level + this.stack.length + delta)}`
|
|
101
|
+
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
get lastCharCode () {
|
|
105
|
+
|
|
106
|
+
const {text} = this
|
|
107
|
+
|
|
108
|
+
return text.charCodeAt (text.length - 1)
|
|
109
|
+
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
openElement (name) {
|
|
113
|
+
|
|
114
|
+
if (this.stack.length !== 0) {
|
|
115
|
+
if (this.attrSpace && this.lastCharCode === CH_QQ) this.newLine (-1)
|
|
116
|
+
if (this.isOpening) this.text += `>`
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (this.space && this.text) this.newLine ()
|
|
120
|
+
|
|
121
|
+
this.text += `<${name}`
|
|
122
|
+
this.stack.push (name)
|
|
123
|
+
|
|
124
|
+
this.isOpening = true
|
|
125
|
+
|
|
126
|
+
return this
|
|
127
|
+
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
writeAttribute (name, value) {
|
|
131
|
+
|
|
132
|
+
if (!this.isOpening) throw Error ('No attribute allowed at this point')
|
|
133
|
+
|
|
134
|
+
if (typeof name !== 'string') throw Error ('The attribute name must be a string, not ' + (typeof name))
|
|
135
|
+
|
|
136
|
+
if (typeof value !== 'string') throw Error ('The attribute value must be a string, not ' + (typeof value))
|
|
137
|
+
|
|
138
|
+
if (this.attrSpace) {
|
|
139
|
+
|
|
140
|
+
this.newLine (-1)
|
|
141
|
+
|
|
142
|
+
this.text += this.attrSpace
|
|
143
|
+
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
|
|
147
|
+
this.text += ' '
|
|
148
|
+
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
this.text += `${name}="${this.ESC_ATTR.escape (value)}"`
|
|
152
|
+
|
|
153
|
+
return this
|
|
154
|
+
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
writeCharacters (value) {
|
|
158
|
+
|
|
159
|
+
if (this.stack.length === 0) throw Error ('No element started yet')
|
|
160
|
+
|
|
161
|
+
if (typeof value !== 'string') throw Error ('The text content must be a string, not ' + (typeof value))
|
|
162
|
+
|
|
163
|
+
if (value.length === 0) return this
|
|
164
|
+
|
|
165
|
+
if (this.isOpening) {
|
|
166
|
+
if (this.attrSpace && this.lastCharCode === CH_QQ) this.newLine (-1)
|
|
167
|
+
this.text += `>`
|
|
168
|
+
this.isOpening = false
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
this.text += this.ESC_BODY.escape (value)
|
|
172
|
+
|
|
173
|
+
return this
|
|
174
|
+
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
closeElement () {
|
|
178
|
+
|
|
179
|
+
const name = this.stack.pop ()
|
|
180
|
+
|
|
181
|
+
if (this.isOpening) {
|
|
182
|
+
if (this.attrSpace && this.lastCharCode === CH_QQ) this.newLine ()
|
|
183
|
+
this.text += ` />`
|
|
184
|
+
this.isOpening = false
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
if (this.space && this.lastCharCode === CH_GT) this.newLine ()
|
|
188
|
+
this.text += `</${name}>`
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return this
|
|
192
|
+
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
writeNode (node) {
|
|
196
|
+
|
|
197
|
+
if (node.type !== SAXEvent.TYPES.END_ELEMENT) return this.writeCharacters (node.src)
|
|
198
|
+
|
|
199
|
+
this.openElement (node.name)
|
|
200
|
+
|
|
201
|
+
if (this.stack.length === 1) {
|
|
202
|
+
|
|
203
|
+
const {namespacesMap} = node; if (namespacesMap != null) {
|
|
204
|
+
|
|
205
|
+
let min = Infinity; for (const name of namespacesMap.keys ()) {
|
|
206
|
+
|
|
207
|
+
const {length} = name
|
|
208
|
+
|
|
209
|
+
if (min > length) min = length
|
|
210
|
+
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
min += 2
|
|
214
|
+
|
|
215
|
+
const prefixes = new Set ()
|
|
216
|
+
|
|
217
|
+
const checkName = name => {
|
|
218
|
+
|
|
219
|
+
if (name.length < min) return
|
|
220
|
+
|
|
221
|
+
const pos = name.indexOf (':'); if (pos === -1) return
|
|
222
|
+
|
|
223
|
+
const prefix = name.substring (0, pos); if (!namespacesMap.has (prefix)) return
|
|
224
|
+
|
|
225
|
+
prefixes.add (prefix)
|
|
226
|
+
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const checkNames = n => {
|
|
230
|
+
|
|
231
|
+
checkName (n.name)
|
|
232
|
+
|
|
233
|
+
for (const [name, value] of n.attributes.entries ()) {
|
|
234
|
+
checkName (name)
|
|
235
|
+
checkName (value)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
for (const child of n.children) if (child.type === SAXEvent.TYPES.END_ELEMENT) checkNames (child); else checkName (child.src)
|
|
239
|
+
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
checkNames (node)
|
|
243
|
+
|
|
244
|
+
for (const prefix of prefixes.values ())
|
|
245
|
+
|
|
246
|
+
this.writeAttribute ('xmlns:' + prefix, namespacesMap.get (prefix))
|
|
247
|
+
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
for (const [name, value] of node.attributes.entries ()) this.writeAttribute (name, value)
|
|
253
|
+
|
|
254
|
+
for (const child of node.children) this.writeNode (child)
|
|
255
|
+
|
|
256
|
+
this.closeElement ()
|
|
257
|
+
|
|
258
|
+
return this
|
|
259
|
+
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
writeXMLDecl ({encoding, standalone} = {}) {
|
|
263
|
+
|
|
264
|
+
if (this.stack.length !== 0) throw Error ('The document is already started')
|
|
265
|
+
|
|
266
|
+
this.text += '<?xml version="1.0"'
|
|
267
|
+
|
|
268
|
+
if (encoding != null) this.text += ` encoding="${encoding}"`
|
|
269
|
+
|
|
270
|
+
if (standalone != null) this.text += ` standalone="${standalone ? 'yes' : 'no'}"`
|
|
271
|
+
|
|
272
|
+
this.text += '?>'
|
|
273
|
+
|
|
274
|
+
return this
|
|
275
|
+
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
module.exports = XMLPrinter
|