Skip to content

Instantly share code, notes, and snippets.

@kesor
Last active November 18, 2019 22:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kesor/e4dc884e37554b3b3402d378bde376b2 to your computer and use it in GitHub Desktop.
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 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