/* * JXON.js * Ratatosk * * Created by Alexander Ljungberg on March 15th, 2012. * * Public domain JXON implementation from algorithm #3 of: * https://developer.mozilla.org/en/Parsing_and_serializing_XML * * Any copyright is dedicated to the Public Domain. * * Modified by Andrew (Pat) Patterson, 2015 from original at * https://github.com/wireload/Ratatosk/blob/master/jxon.js * to preserve case of element and attribute names */ JXON = function() { }; JXON.buildValue = function(sValue) { if (/^\s*$/.test(sValue)) return null; if (/^(true|false)$/i.test(sValue)) return sValue.toLowerCase() === "true"; if (isFinite(sValue)) return parseFloat(sValue); // Don't do this - it'll parse anything that looks like a date and get the timezone wrong. // https://bugzilla.mozilla.org/show_bug.cgi?id=693077 //if (isFinite(Date.parse(sValue))) // return new Date(sValue); return sValue; }; JXON.fromXML = function(xmlString) { return JXON.getJXONData((new DOMParser()).parseFromString(xmlString, "text/xml")); }; JXON.getJXONData = function(oXMLParent) { var vResult = /* put here the default value for empty nodes! */ null, nLength = 0, sCollectedTxt = ""; if (oXMLParent.hasAttributes && oXMLParent.hasAttributes()) { vResult = {}; for (nLength; nLength < oXMLParent.attributes.length; nLength++) { oItAttr = oXMLParent.attributes.item(nLength); vResult["@" + oItAttr.nodeName] = JXON.buildValue(oItAttr.value.replace(/^\s+|\s+$/g, "")); } } if (oXMLParent.hasChildNodes()) { for (var oItChild, sItKey, sItVal, nChildId = 0; nChildId < oXMLParent.childNodes.length; nChildId++) { oItChild = oXMLParent.childNodes.item(nChildId); if (oItChild.nodeType === 4) { sCollectedTxt += oItChild.nodeValue; } /* nodeType is "CDATASection" (4) */ else if (oItChild.nodeType === 3) { sCollectedTxt += oItChild.nodeValue.replace(/^\s+|\s+$/g, ""); } /* nodeType is "Text" (3) */ else if (oItChild.nodeType === 1 && !oItChild.prefix) { /* nodeType is "Element" (1) */ if (nLength === 0) vResult = {}; sItKey = oItChild.nodeName; sItVal = JXON.getJXONData(oItChild); if (vResult.hasOwnProperty(sItKey)) { if (vResult[sItKey].constructor !== Array) vResult[sItKey] = [vResult[sItKey]]; vResult[sItKey].push(sItVal); } else { vResult[sItKey] = sItVal; nLength++; } } } } if (sCollectedTxt) nLength > 0 ? vResult.keyValue = JXON.buildValue(sCollectedTxt) : vResult = JXON.buildValue(sCollectedTxt); /* if (nLength > 0) { Object.freeze(vResult); } */ return vResult; }; JXON.loadObj = function(oParentObj, oParentEl, oNewDoc) { var nSameIdx, vValue, oChild; for (var sName in oParentObj) { vValue = oParentObj[sName]; if (sName === "keyValue") { if (vValue !== null && vValue !== true) oParentEl.appendChild(oNewDoc.createTextNode(String(vValue))); } else if (sName.charAt(0) === "@") oParentEl.setAttribute(sName.slice(1), vValue); else { oChild = oNewDoc.createElement(sName); if (vValue && vValue.constructor === Date) oChild.appendChild(oNewDoc.createTextNode(vValue.toGMTString())); else if (vValue && vValue.constructor === Array) { for (nSameIdx = 0; nSameIdx < vValue.length; nSameIdx++) JXON.loadObj(vValue[nSameIdx], oChild); } else if (vValue && vValue instanceof Object) { JXON.loadObj(vValue, oChild, oNewDoc); } else if (vValue !== null && vValue !== true) oChild.appendChild(oNewDoc.createTextNode(vValue.toString())); oParentEl.appendChild(oChild); // CPLog.error("Document: " + (new XMLSerializer()).serializeToString(oNewDoc)); } } }; JXON.toXML = function(oJXONObj, rootName) { var oNewDoc = document.implementation.createDocument("", "", null), rootNode = oNewDoc.createElement(rootName || 'xml'); oNewDoc.appendChild(rootNode); JXON.loadObj(oJXONObj, rootNode, oNewDoc); return (new XMLSerializer()).serializeToString(oNewDoc); };