Last active
November 18, 2019 22:48
-
-
Save kesor/e4dc884e37554b3b3402d378bde376b2 to your computer and use it in GitHub Desktop.
Slightly cleaned up version of xml2json by Stefan Goessner/2006 http://goessner.net
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* This work is licensed under Creative Commons GNU LGPL License. | |
License: http://creativecommons.org/licenses/LGPL/2.1/ | |
Version: 0.9 | |
Author: Stefan Goessner/2006 | |
Web: http://goessner.net/ | |
Original file: https://goessner.net/download/prj/jsonxml/ | |
*/ | |
function xml2json(xml) { | |
const X = { | |
toObj: function (xml) { | |
let o = {}; | |
if (xml.nodeType == Node.ELEMENT_NODE) { | |
if (xml.attributes.length) | |
for (let i = 0; i < xml.attributes.length; i++) | |
o["@" + xml.attributes[i].nodeName] = (xml.attributes[i].nodeValue || "").toString(); | |
if (xml.firstChild) { // element has child nodes .. | |
let textChild = 0, cdataChild = 0, hasElementChild = false; | |
for (let n = xml.firstChild; n; n = n.nextSibling) { | |
if (n.nodeType == Node.ELEMENT_NODE) hasElementChild = true; | |
else if (n.nodeType == Node.TEXT_NODE && n.nodeValue.trim()) textChild++; // non-whitespace text | |
else if (n.nodeType == Node.CDATA_SECTION_NODE) cdataChild++; // cdata section node | |
} | |
if (hasElementChild) { | |
if (textChild < 2 && cdataChild < 2) { // structured element with evtl. a single text or/and cdata node .. | |
for (let n = xml.firstChild; n; n = n.nextSibling) { | |
if (n.nodeType == Node.TEXT_NODE) { // text node | |
if (n.nodeValue.trim()) | |
o["#text"] = X.escape(n.nodeValue); | |
} | |
else if (n.nodeType == Node.CDATA_SECTION_NODE) // cdata node | |
o["#cdata"] = X.escape(n.nodeValue); | |
else if (o[n.nodeName]) { // multiple occurence of element .. | |
if (o[n.nodeName] instanceof Array) | |
o[n.nodeName][o[n.nodeName].length] = X.toObj(n); | |
else | |
o[n.nodeName] = [o[n.nodeName], X.toObj(n)]; | |
} | |
else // first occurence of element.. | |
o[n.nodeName] = X.toObj(n); | |
} | |
} | |
else { // mixed content | |
if (!xml.attributes.length) | |
o = X.escape(X.innerXml(xml)); | |
else | |
o["#text"] = X.escape(X.innerXml(xml)); | |
} | |
} | |
else if (textChild) { // pure text | |
if (!xml.attributes.length) | |
o = X.escape(X.innerXml(xml)); | |
else | |
o["#text"] = X.escape(X.innerXml(xml)); | |
} | |
else if (cdataChild) { // cdata | |
if (cdataChild > 1) | |
o = X.escape(X.innerXml(xml)); | |
else | |
for (let n = xml.firstChild; n; n = n.nextSibling) | |
o["#cdata"] = X.escape(n.nodeValue); | |
} | |
} | |
if (!xml.attributes.length && !xml.firstChild) o = null; | |
} | |
else if (xml.nodeType == Node.DOCUMENT_NODE) { // document.node | |
o = X.toObj(xml.documentElement); | |
} | |
else | |
console.error("unhandled node type: " + xml.nodeType); | |
return o; | |
}, | |
toJson: function (o, name) { | |
let json = name ? ("\"" + name + "\"") : ""; | |
if (o instanceof Array) { | |
o = o.map(m => X.toJson(m, "")); | |
json += (name ? ":[" : "[") + (o.length > 1 ? o.join(",") : o.join("")) + "]"; | |
} | |
else if (o == null) | |
json += (name && ":") + "null"; | |
else if (typeof (o) == "object") { | |
let arr = []; | |
for (let m in o) | |
arr[arr.length] = X.toJson(o[m], m); | |
json += (name ? ":" : "") + "{" + (arr.length > 1 ? arr.join(",") : arr.join("")) + "}"; | |
} | |
else if (typeof (o) == "string") | |
json += (name && ":") + "\"" + o.toString() + "\""; | |
else | |
json += (name && ":") + o.toString(); | |
return json; | |
}, | |
innerXml: function (node) { | |
let s = "" | |
if ("innerHTML" in node) | |
s = node.innerHTML; | |
else { | |
const asXml = function (n) { | |
let s = ""; | |
if (n.nodeType == Node.TEXT_NODE) | |
s += n.nodeValue; | |
else if (n.nodeType == Node.CDATA_SECTION_NODE) | |
s += "<![CDATA[" + n.nodeValue + "]]>"; | |
else if (n.nodeType == Node.ELEMENT_NODE) { | |
s += "<" + n.nodeName; | |
n.attributes.map(attr => { s += " " + attr.nodeName + "=\"" + (attr.nodeName || "").toString() + "\""; }) | |
if (n.firstChild) { | |
s += ">"; | |
for (let c = n.firstChild; c; c = c.nextSibling) | |
s += asXml(c); | |
s += "</" + n.nodeName + ">"; | |
} | |
else | |
s += "/>"; | |
} | |
return s; | |
}; | |
for (let c = node.firstChild; c; c = c.nextSibling) | |
s += asXml(c); | |
} | |
return s; | |
}, | |
escape: function (txt) { | |
return txt.replace(/[\\]/g, "\\\\") | |
.replace(/[\"]/g, '\\"') | |
.replace(/[\n]/g, '\\n') | |
.replace(/[\r]/g, '\\r'); | |
} | |
}; | |
if (xml.nodeType == Node.DOCUMENT_NODE) { | |
xml = xml.documentElement; | |
} | |
return JSON.parse('{' + X.toJson(X.toObj(xml), xml.nodeName) + '}'); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment