craydent-xml-to-json
Version:
Node module to parse xml into json
207 lines (204 loc) • 8.64 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.__processChildren = __processChildren;
exports.__processSiblings = __processSiblings;
exports.default = xmlToJson;
const craydent_error_1 = require("craydent.error");
const craydent_filltemplate_1 = require("craydent.filltemplate");
const craydent_isarray_1 = require("craydent.isarray");
const craydent_isstring_1 = require("craydent.isstring");
const craydent_strip_1 = require("craydent.strip");
const craydent_suid_1 = require("craydent.suid");
const __processAttributes_1 = require("../private/__processAttributes");
const craydent_merge_1 = require("craydent.merge");
const craydent_isempty_1 = require("craydent.isempty");
const craydent_isnull_1 = require("craydent.isnull");
function __processChildren(name, children, xml, refs, ignoreAttributes) {
let child, i = 0, obj = {};
let nodename = name;
if (!children.length && !ignoreAttributes) {
const attributes = (0, __processAttributes_1.default)(xml, refs);
if ((0, craydent_isempty_1.default)(attributes)) {
obj[nodename] = '';
}
else {
obj[nodename] = (0, __processAttributes_1.default)(xml, refs);
}
}
while (child = children[i++]) {
let index = child.indexOf('>'), lindex = child.lastIndexOf('</'), attributes = ignoreAttributes ? {} : (0, __processAttributes_1.default)(child, refs), childXML = (0, craydent_strip_1.default)(child.substring(index + 1, lindex), '\n').trim();
if (children.length == 1) {
// @ts-ignore
childXML = xmlToJson(childXML, ignoreAttributes, refs);
if (!(0, craydent_isstring_1.default)(childXML)) {
childXML = (0, craydent_merge_1.default)(attributes, childXML);
}
obj[nodename] = childXML;
}
else {
obj[nodename] = obj[nodename] || [];
// @ts-ignore
childXML = xmlToJson(childXML, ignoreAttributes, refs);
if (!(0, craydent_isstring_1.default)(childXML)) {
childXML = (0, craydent_merge_1.default)(attributes, childXML);
}
obj[nodename].push(childXML);
}
}
return obj;
}
function __processSiblings(xml, refs, ignoreAttributes) {
let parts = xml.split('<'), obj = {}, tag = "", node = "", etag, tagCount = 0;
obj['#text'] = obj['#text'] || "";
for (let i = 0; i < parts.length; i++) {
let part = parts[i];
if (!part) {
continue;
}
/* istanbul ignore else */
if (!~part.indexOf('/>')) {
/* istanbul ignore else */
if (!tag) {
etag = part.indexOf('>');
if (!~etag) {
if (!i) {
obj['#text'] += (0, craydent_filltemplate_1.default)((0, craydent_strip_1.default)(part, ['\n', ' ']), refs);
}
else {
node += part;
}
continue;
}
tag = part.split(/\s|>/)[0];
tagCount++;
node += `<${part}`;
continue;
}
else if (part.indexOf(tag) == 0) {
tagCount++;
}
else if (part.indexOf(`/${tag}>`) == 0) {
tagCount--;
}
}
else if (!tagCount) {
tag = part.replace('/>', '').trim();
}
etag = part.indexOf(`/${tag}>`);
if (!~etag) {
let selfClosing = new RegExp(`${tag}(\\s*)/>`);
const matching = part.match(selfClosing);
if (matching && !(0, craydent_isnull_1.default)(matching[1])) {
etag = part.search(selfClosing) + matching[1].length;
}
}
if (!tagCount && ~etag) {
let text = (0, craydent_strip_1.default)(part.substr(etag + tag.length + 2), ['\n', ' ']);
if (text) {
obj['#text'] += (0, craydent_filltemplate_1.default)(text, refs);
}
node += `<${part.substring(0, etag + tag.length + 2)}`;
if (obj[tag]) {
if (!(0, craydent_isarray_1.default)(obj[tag])) {
obj[tag] = [obj[tag]];
}
// @ts-ignore
let child = xmlToJson(node, ignoreAttributes, refs);
obj['#text'] += child['#text'] || '';
obj[tag].push(child[tag]);
}
else {
// @ts-ignore
obj = (0, craydent_merge_1.default)(obj, xmlToJson(node, ignoreAttributes, refs));
}
tag = "", node = "";
}
else {
node += `<${part}`;
}
}
if (!obj['#text'] && !(obj['#text'] = (0, craydent_filltemplate_1.default)(node, refs))) {
delete obj['#text'];
}
return obj;
}
function xmlToJson(xml, ignoreAttributes, _refs) {
/*|{
"info": "Converts XML to JSON",
"category": "XML to JSON",
"parameters":[
{"xml": "(String|XMLDocument) XML string or XML DOM"},
{"ignoreAttributes?": "(Bool) Flag to ignore attributes"}],
"overloads":[],
"url": "http://www.craydent.com/library/1.9.3/docs#xmlToJson",
"returnType": "(Object)"
}|*/
try {
xml = xml.outerHTML || xml;
let ids = [], rtn = xml;
let raws = xml.match(/<\!\[CDATA\[(.*?)\]\]>/g) || [];
xmlToJson.refs = xmlToJson.refs || {};
for (let i = 0, len = raws.length; i < len; i++) {
let id = (0, craydent_suid_1.default)();
ids.push(id);
xmlToJson.refs[id] = raws[i].replace(/<\!\[CDATA\[(.*?)\]\]>/, '$1');
xml = xml.replace(raws[i], `\${${id}}`);
}
xml = (0, craydent_strip_1.default)(xml.replace(/<\?.*?\?>/, ''), '\n').replace(/>\s*?\n\s*/g, '>');
let index = xml.indexOf('>'), nodename = xml.substring(0, index + 1).replace(/<([^\s\/]*)?(?:\s*?.*?)>/, '$1').replace(/<(\S*)?(?:\s*?.*?)>/, '$1');
let hasSiblings = false;
/* istanbul ignore else */
if (nodename) {
let parts = xml.split(nodename), child = "", children = [], openCount = 0;
// break down construct string of children
for (let i = 0, len = parts.length; i < len; i++) {
let part = parts[i] = (0, craydent_strip_1.default)(parts[i], '\n');
if (!(openCount) && (part == ">" /* || part == "><" */)) {
child += ">";
children.push(child);
child = part.substr(1) + nodename;
}
else {
/* istanbul ignore else */
if (part.slice(-1) == "<") {
openCount++;
}
else if (~part.indexOf("</") || part.slice(-2) == "/>") {
openCount--;
let offset = 2;
if (part == "/>") {
offset = 1;
}
if (!openCount && i != len - offset) {
hasSiblings = true;
}
}
child += part + nodename;
}
}
if (children.length == 1 && children[0] == xml && hasSiblings) {
children = [];
}
// when there are different nodes
const xmlWithoutSelfClosing = xml.replace(new RegExp(`<${nodename}[^>]*?/>`, 'g'), '');
let scount = (xmlWithoutSelfClosing.match(new RegExp(`<${nodename}.*?>`, 'g')) || []).length, ecount = (xmlWithoutSelfClosing.match(new RegExp(`</${nodename}>`, 'g')) || []).length;
if (xmlWithoutSelfClosing && !children.length && scount == ecount) {
rtn = __processSiblings(xml, xmlToJson.refs, ignoreAttributes);
}
else {
rtn = __processChildren(nodename, children, xml, xmlToJson.refs, ignoreAttributes);
}
}
else if ((0, craydent_isstring_1.default)(rtn)) {
rtn = (0, craydent_filltemplate_1.default)(rtn, xmlToJson.refs);
}
for (let i = 0, len = ids.length; i < len; i++) {
delete xmlToJson.refs[ids[i]];
}
return rtn;
}
catch (e) /* istanbul ignore next */ {
craydent_error_1.default && (0, craydent_error_1.default)('xmlToJson', e);
return null;
}
}