Add the upstream implementation which I've ported from JavaScript

See: https://goessner.net/download/prj/jsonxml/
This commit is contained in:
R Tyler Croy 2020-10-01 10:08:21 -07:00
parent f90fef495e
commit 2336f3a6f8
No known key found for this signature in database
GPG Key ID: E5C92681BEF6CEA2
3 changed files with 334 additions and 0 deletions

45
contrib/json2xml.js Normal file
View File

@ -0,0 +1,45 @@
/* 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/
*/
function json2xml(o, tab) {
var toXml = function(v, name, ind) {
var xml = "";
if (v instanceof Array) {
for (var i=0, n=v.length; i<n; i++)
xml += ind + toXml(v[i], name, ind+"\t") + "\n";
}
else if (typeof(v) == "object") {
var hasChild = false;
xml += ind + "<" + name;
for (var m in v) {
if (m.charAt(0) == "@")
xml += " " + m.substr(1) + "=\"" + v[m].toString() + "\"";
else
hasChild = true;
}
xml += hasChild ? ">" : "/>";
if (hasChild) {
for (var m in v) {
if (m == "#text")
xml += v[m];
else if (m == "#cdata")
xml += "<![CDATA[" + v[m] + "]]>";
else if (m.charAt(0) != "@")
xml += toXml(v[m], m, ind+"\t");
}
xml += (xml.charAt(xml.length-1)=="\n"?ind:"") + "</" + name + ">";
}
}
else {
xml += ind + "<" + name + ">" + v.toString() + "</" + name + ">";
}
return xml;
}, xml="";
for (var m in o)
xml += toXml(o[m], m, "");
return tab ? xml.replace(/\t/g, tab) : xml.replace(/\t|\n/g, "");
}

155
contrib/xml2json.js Normal file
View File

@ -0,0 +1,155 @@
/* 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/
*/
function xml2json(xml, tab) {
var X = {
toObj: function(xml) {
var o = {};
if (xml.nodeType==1) { // element node ..
if (xml.attributes.length) // element with attributes ..
for (var i=0; i<xml.attributes.length; i++)
o["@"+xml.attributes[i].nodeName] = (xml.attributes[i].nodeValue||"").toString();
if (xml.firstChild) { // element has child nodes ..
var textChild=0, cdataChild=0, hasElementChild=false;
for (var n=xml.firstChild; n; n=n.nextSibling) {
if (n.nodeType==1) hasElementChild = true;
else if (n.nodeType==3 && n.nodeValue.match(/[^ \f\n\r\t\v]/)) textChild++; // non-whitespace text
else if (n.nodeType==4) cdataChild++; // cdata section node
}
if (hasElementChild) {
if (textChild < 2 && cdataChild < 2) { // structured element with evtl. a single text or/and cdata node ..
X.removeWhite(xml);
for (var n=xml.firstChild; n; n=n.nextSibling) {
if (n.nodeType == 3) // text node
o["#text"] = X.escape(n.nodeValue);
else if (n.nodeType == 4) // 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 (var 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==9) { // document.node
o = X.toObj(xml.documentElement);
}
else
alert("unhandled node type: " + xml.nodeType);
return o;
},
toJson: function(o, name, ind) {
var json = name ? ("\""+name+"\"") : "";
if (o instanceof Array) {
for (var i=0,n=o.length; i<n; i++)
o[i] = X.toJson(o[i], "", ind+"\t");
json += (name?":[":"[") + (o.length > 1 ? ("\n"+ind+"\t"+o.join(",\n"+ind+"\t")+"\n"+ind) : o.join("")) + "]";
}
else if (o == null)
json += (name&&":") + "null";
else if (typeof(o) == "object") {
var arr = [];
for (var m in o)
arr[arr.length] = X.toJson(o[m], m, ind+"\t");
json += (name?":{":"{") + (arr.length > 1 ? ("\n"+ind+"\t"+arr.join(",\n"+ind+"\t")+"\n"+ind) : arr.join("")) + "}";
}
else if (typeof(o) == "string")
json += (name&&":") + "\"" + o.toString() + "\"";
else
json += (name&&":") + o.toString();
return json;
},
innerXml: function(node) {
var s = ""
if ("innerHTML" in node)
s = node.innerHTML;
else {
var asXml = function(n) {
var s = "";
if (n.nodeType == 1) {
s += "<" + n.nodeName;
for (var i=0; i<n.attributes.length;i++)
s += " " + n.attributes[i].nodeName + "=\"" + (n.attributes[i].nodeValue||"").toString() + "\"";
if (n.firstChild) {
s += ">";
for (var c=n.firstChild; c; c=c.nextSibling)
s += asXml(c);
s += "</"+n.nodeName+">";
}
else
s += "/>";
}
else if (n.nodeType == 3)
s += n.nodeValue;
else if (n.nodeType == 4)
s += "<![CDATA[" + n.nodeValue + "]]>";
return s;
};
for (var 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');
},
removeWhite: function(e) {
e.normalize();
for (var n = e.firstChild; n; ) {
if (n.nodeType == 3) { // text node
if (!n.nodeValue.match(/[^ \f\n\r\t\v]/)) { // pure whitespace text node
var nxt = n.nextSibling;
e.removeChild(n);
n = nxt;
}
else
n = n.nextSibling;
}
else if (n.nodeType == 1) { // element node
X.removeWhite(n);
n = n.nextSibling;
}
else // any other node
n = n.nextSibling;
}
return e;
}
};
if (xml.nodeType == 9) // document node
xml = xml.documentElement;
var json = X.toJson(X.toObj(X.removeWhite(xml)), xml.nodeName, "\t");
return "{\n" + tab + (tab ? json.replace(/\t/g, tab) : json.replace(/\t|\n/g, "")) + "\n}";
}

134
contrib/xmljson_test.html Normal file
View File

@ -0,0 +1,134 @@
<html>
<head>
<title> XML/JSON - Tests </title>
<script type="text/javascript" src="xml2json.js"></script>
<script type="text/javascript" src="json2xml.js"></script>
<script type="text/javascript">
var xml=[
'<e/>',
'<e>text</e>',
'<e name="value" />',
'<e name="value">text</e>',
'<e> <a>text</a> <b>text</b> </e>',
'<e> <a>text</a> <a>text</a> </e>',
'<e> text <a>text</a> </e>',
'<a>hello</a>',
'<a x="y">hello</a>',
'<a id="a"><b id="b">hey!</b></a>',
'<a>x<c/>y</a>',
'<x u=""/>',
'<html>'+
' <head>'+
' <title>Xml/Json</title>'+
' <meta name="x" content="y" />'+
' </head>'+
' <body>'+
' </body>'+
'</html>',
'<ol class="xoxo">'+
' <li>Subject 1'+
' <ol>'+
' <li>subpoint a</li>'+
' <li>subpoint b</li>'+
' </ol>'+
' </li>'+
' <li><span>Subject 2</span>'+
' <ol compact="compact">'+
' <li>subpoint c</li>'+
' <li>subpoint d</li>'+
' </ol>'+
' </li>'+
'</ol>',
'<span class="vevent">'+
' <a class="url" href="http://www.web2con.com/">'+
' <span class="summary">Web 2.0 Conference</span>'+
' <abbr class="dtstart" title="2005-10-05">October 5</abbr>'+
' <abbr class="dtend" title="2005-10-08">7</abbr>'+
' <span class="location">Argent Hotel, San Francisco, CA</span>'+
' </a>'+
'</span>',
'<e>\n'+
' <![CDATA[ .. some data .. ]]>\n'+
'</e>',
'<e>\n'+
' <a />\n' +
' <![CDATA[ .. some data .. ]]>\n'+
' <b />\n' +
'</e>',
'<e>\n'+
' some text\n' +
' <![CDATA[ .. some data .. ]]>\n'+
' more text\n' +
'</e>',
'<e>\n'+
' some text\n' +
' <![CDATA[ .. some data .. ]]>\n'+
' <a />\n' +
'</e>',
'<e>\n'+
' <![CDATA[ .. some data .. ]]>\n'+
' <![CDATA[ .. more data .. ]]>\n'+
'</e>'
];
function parseXml(xml) {
var dom = null;
if (window.DOMParser) {
try {
dom = (new DOMParser()).parseFromString(xml, "text/xml");
}
catch (e) { dom = null; }
}
else if (window.ActiveXObject) {
try {
dom = new ActiveXObject('Microsoft.XMLDOM');
dom.async = false;
if (!dom.loadXML(xml)) // parse error ..
window.alert(dom.parseError.reason + dom.parseError.srcText);
}
catch (e) { dom = null; }
}
else
alert("oops");
return dom;
}
window.onload = function() {
var json;
eval('a = {"e":null}');
for (var i=0; i<xml.length; i++) {
show(xml[i] + "\n\n" +
(json = xml2json(parseXml(xml[i]), " ")) + "\n\n" +
json2xml(eval('json='+json)));
}
}
function show(s) { document.getElementById("out").innerHTML += (s+"\n").replace(/&/g, "&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/\n/g, "<br/>") + "<hr/>"; }
</script>
</head>
<body>
<pre id="out"></pre>
</body>
</html>