diff --git a/server/core/xml/XmlParser.js b/server/core/xml/XmlParser.js index 38a3855..a0d9a01 100644 --- a/server/core/xml/XmlParser.js +++ b/server/core/xml/XmlParser.js @@ -352,7 +352,9 @@ class XmlParser extends NodeBase { return this.selectFirst(selector, self); } - toJson(format = false) { + toJson(options = {}) { + const {format = false} = options; + if (format) return JSON.stringify(this.rawNodes, null, 2); else @@ -395,7 +397,11 @@ class XmlParser extends NodeBase { if (node.attrs) { for (const [attrName, attrValue] of node.attrs) { - attrs += ` ${attrName}="${attrValue}"`; + if (typeof(attrValue) === 'string') + attrs += ` ${attrName}="${attrValue}"`; + else + if (attrValue) + attrs += ` ${attrName}`; } } @@ -410,11 +416,11 @@ class XmlParser extends NodeBase { close = (deepType === NODE ? ' '.repeat(depth) : '') + close + '\n'; } } else if (node.type === TEXT) { - body = node.value; + body = node.value || ''; } else if (node.type === CDATA) { - // + body = ``; } else if (node.type === COMMENT) { - // + body = ``; } result += `${open}${body}${close}`; @@ -429,7 +435,89 @@ class XmlParser extends NodeBase { return out; } - fromSrtring() { + fromString(xmlString, options = {}, pickNode = () => true) { + const parsed = []; + const root = this.createNode(parsed); + let node = root; + + let route = ''; + let routeStack = []; + let ignoreNode = false; + + const {lowerCase = false, whiteSpace = false} = options; + + const onStartNode = (tag, tail, singleTag, cutCounter, cutTag) => {// eslint-disable-line no-unused-vars + if (tag == '?xml') + return; + + route += `/${tag}`; + ignoreNode = !pickNode(route); + + const newNode = this.createNode(tag); + + routeStack.push({tag, route, ignoreNode, node: newNode}); + + if (ignoreNode) + return; + + if (tail) { + const parsedAttrs = sax.getAttrsSync(tail, lowerCase); + const attrs = new Map(); + for (const attr of parsedAttrs.values()) { + attrs.set(attr.fn, attr.value); + } + + if (attrs.size) + newNode.attrs = attrs; + } + + if (!node.value) + node.value = []; + node.value.push(newNode.raw); + node = newNode; + }; + + const onEndNode = (tag, tail, singleTag, cutCounter, cutTag) => {// eslint-disable-line no-unused-vars + if (routeStack.length && routeStack[routeStack.length - 1].tag === tag) { + routeStack.pop(); + + if (routeStack.length) { + const last = routeStack[routeStack.length - 1]; + route = last.route; + ignoreNode = last.ignoreNode; + node = last.node; + } else { + route = ''; + ignoreNode = false; + node = root; + } + } + } + + const onTextNode = (text, cutCounter, cutTag) => {// eslint-disable-line no-unused-vars + if (ignoreNode) + return; + + if (!whiteSpace && text.trim() == '') + return; + + if (!node.value) + node.value = []; + + node.value.push(this.createText(text).raw); + }; + + const onCdata = (tagData, cutCounter, cutTag) => {// eslint-disable-line no-unused-vars + } + + const onComment = (tagData, cutCounter, cutTag) => {// eslint-disable-line no-unused-vars + } + + sax.parseSync(xmlString, { + onStartNode, onEndNode, onTextNode, onCdata, onComment, lowerCase + }); + + this.rawNodes = parsed; } } diff --git a/server/core/xml/sax.js b/server/core/xml/sax.js index 07b5a55..1525ac7 100644 --- a/server/core/xml/sax.js +++ b/server/core/xml/sax.js @@ -281,7 +281,7 @@ async function parse(xstr, options) { } function getAttrsSync(tail, lowerCase = true) { - let result = {}; + let result = new Map(); let name = ''; let value = ''; let vOpen = ''; @@ -300,7 +300,7 @@ function getAttrsSync(tail, lowerCase = true) { [ns, name] = fn.split(':'); } - result[name] = {value, ns, fn}; + result.set(fn, {value, ns, name, fn}); } name = ''; value = '';