Преглед изворни кода

Работа над XmlParser

Book Pauk пре 2 година
родитељ
комит
8f4dec510c
2 измењених фајлова са 96 додато и 8 уклоњено
  1. 94 6
      server/core/xml/XmlParser.js
  2. 2 2
      server/core/xml/sax.js

+ 94 - 6
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 = `<![CDATA[${node.value || ''}]]>`;
                 } else if (node.type === COMMENT) {
-                    //
+                    body = `<!--${node.value || ''}-->`;
                 }
 
                 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;        
     }
 }
 

+ 2 - 2
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 = '';