Files
liberama/server/core/xmlParser.js
2020-12-08 19:31:00 +07:00

143 lines
3.8 KiB
JavaScript

const sax = require('./sax');
function formatXml(xmlParsed, encoding = 'utf-8', textFilterFunc) {
let out = `<?xml version="1.0" encoding="${encoding}"?>`;
out += formatXmlNode(xmlParsed, textFilterFunc);
return out;
}
function formatXmlNode(node, textFilterFunc) {
textFilterFunc = (textFilterFunc ? textFilterFunc : text => text);
const formatNode = (node, name) => {
let out = '';
if (Array.isArray(node)) {
for (const n of node) {
out += formatNode(n);
}
} else if (typeof node == 'string') {
if (name)
out += `<${name}>${textFilterFunc(node)}</${name}>`;
else
out += textFilterFunc(node);
} else {
if (node._n)
name = node._n;
let attrs = '';
if (node._attrs) {
for (let attrName in node._attrs) {
attrs += ` ${attrName}="${node._attrs[attrName]}"`;
}
}
let tOpen = '';
let tBody = '';
let tClose = '';
if (name)
tOpen += `<${name}${attrs}>`;
if (node.hasOwnProperty('_t'))
tBody += textFilterFunc(node._t);
for (let nodeName in node) {
if (nodeName && nodeName[0] == '_' && nodeName != '_a')
continue;
const n = node[nodeName];
tBody += formatNode(n, nodeName);
}
if (name)
tClose += `</${name}>`;
out += `${tOpen}${tBody}${tClose}`;
}
return out;
}
return formatNode(node);
}
function parseXml(xmlString, lowerCase = true) {
let result = {};
let node = result;
const onTextNode = (text, cutCounter, cutTag) => {// eslint-disable-line no-unused-vars
node._t = text;
};
const onStartNode = (tag, tail, singleTag, cutCounter, cutTag) => {// eslint-disable-line no-unused-vars
if (tag == '?xml')
return;
const newNode = {_n: tag, _p: node};
if (tail) {
const parsedAttrs = sax.getAttrsSync(tail, lowerCase);
const atKeys = Object.keys(parsedAttrs);
if (atKeys.length) {
const attrs = {};
for (let i = 0; i < atKeys.length; i++) {
const attrName = atKeys[i];
attrs[parsedAttrs[attrName].fn] = parsedAttrs[attrName].value;
}
newNode._attrs = attrs;
}
}
if (!node._a)
node._a = [];
node._a.push(newNode);
node = newNode;
};
const onEndNode = (tag, tail, singleTag, cutCounter, cutTag) => {// eslint-disable-line no-unused-vars
if (node._p && node._n == tag)
node = node._p;
};
sax.parseSync(xmlString, {
onStartNode, onEndNode, onTextNode, lowerCase
});
if (result._a)
result = result._a[0];
return result;
}
function simplifyXmlParsed(node) {
const simplifyNodeArray = (a) => {
const result = {};
for (let i = 0; i < a.length; i++) {
const child = a[i];
if (child._n && !result[child._n]) {
result[child._n] = {};
if (child._a) {
result[child._n] = simplifyNodeArray(child._a);
}
if (child._t) {
result[child._n]._t = child._t;
}
if (child._attrs) {
result[child._n]._attrs = child._attrs;
}
}
}
return result;
};
return simplifyNodeArray([node]);
}
module.exports = {
formatXml,
formatXmlNode,
parseXml,
simplifyXmlParsed
}