From 09c246d16311d612b65c3ae6d872b12957ebac68 Mon Sep 17 00:00:00 2001 From: Greg Turner Date: Mon, 16 Jan 2017 11:38:35 -0800 Subject: [PATCH 1/2] enhancement: XML sequences support --- jxon.js | 44 ++++++++++++++++++++++++++++++++++++++------ test/spec.js | 22 +++++++++++++++++++++- 2 files changed, 59 insertions(+), 7 deletions(-) diff --git a/jxon.js b/jxon.js index 81548b1..92ce3ea 100644 --- a/jxon.js +++ b/jxon.js @@ -20,7 +20,7 @@ * bugfixes and code cleanup by user @laubstein * https://github.com/tyrasd/jxon/pull/32 * - * adapted for nodejs and npm by @tyrasd (Martin Raifer ) + * adapted for nodejs and npm by @tyrasd (Martin Raifer ) */ (function(root, factory) { @@ -54,7 +54,8 @@ trueIsEmpty: false, autoDate: false, ignorePrefixedNodes: false, - parseValues: false + parseValues: false, + sequenceKey: '_sequence' }; var aCache = []; var rIsNull = /^\s*$/; @@ -228,18 +229,49 @@ } else if (oParentObj.constructor === Date) { oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toISOString())); } - for (var sName in oParentObj) { + + // Pull out properties names + var propNames = Object.getOwnPropertyNames(oParentObj); + + // Look for optional _sequence + if (oParentObj.hasOwnProperty(opts.sequenceKey)) { + + var sequence = oParentObj[opts.sequenceKey]; + + // sort prop names based on _sequence + propNames.sort(function(a, b) { + + // Sort comparator + // find index of A and B + var aIndex = sequence.indexOf(a); + var bIndex = sequence.indexOf(b); + + // If prop not named, put on end + if (aIndex < 0 || bIndex < 0) { + return -1; + } + + // Subtract the indexes + return aIndex - bIndex; + }) + + } + + propNames.forEach(function(sName, index) { vValue = oParentObj[sName]; if ( vValue === undefined ) { - continue; + return; } if ( vValue === null ) { vValue = {}; } + if ( sName === opts.sequenceKey) { + return; + } if (isFinite(sName) || vValue instanceof Function) { - continue; + return; } /* verbosity level is 0 */ @@ -288,7 +320,7 @@ } oParentEl.appendChild(oChild); } - } + }); } this.xmlToJs = this.build = function(oXMLParent, nVerbosity /* optional */ , bFreeze /* optional */ , bNesteAttributes /* optional */ ) { var _nVerb = arguments.length > 1 && typeof nVerbosity === 'number' ? nVerbosity & 3 : /* put here the default verbosity level: */ 1; diff --git a/test/spec.js b/test/spec.js index c179ee9..d55f23c 100644 --- a/test/spec.js +++ b/test/spec.js @@ -76,7 +76,7 @@ describe('JXON', function() { }); var strTwo = JXON.jsToString(JXON.stringToJs('first positionsecond position')); - + assert.equal(strOne, strTwo); }); @@ -156,5 +156,25 @@ describe('JXON', function() { assert.equal(strNull, strEmptyObj); }); + }); + + describe('xml sequences', function() { + it('as property', function () { + var strNull = JXON.jsToString({ + 'SequencedJS': { + 'element2': 2, + 'element1': 1, + '_sequence': ['element1', 'element2'], + 'elementWithSequence': { + 'element1': 1, + 'element2': 2 + } + } + }); + var strEmptyObj = '1212'; + + assert.equal(strNull, strEmptyObj); + }); + }); }); From 510f1b6f3dfd74a7fe80451d39c53d3f6e8e6eac Mon Sep 17 00:00:00 2001 From: Greg Turner Date: Mon, 16 Jan 2017 12:27:29 -0800 Subject: [PATCH 2/2] minified version --- jxon.min.js | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/jxon.min.js b/jxon.min.js index ce7a673..7867a90 100644 --- a/jxon.min.js +++ b/jxon.min.js @@ -20,7 +20,7 @@ * bugfixes and code cleanup by user @laubstein * https://github.com/tyrasd/jxon/pull/32 * - * adapted for nodejs and npm by @tyrasd (Martin Raifer ) + * adapted for nodejs and npm by @tyrasd (Martin Raifer ) */ (function(e,t){if(typeof define==="function"&&define.amd){ // AMD. Register as an anonymous module. @@ -33,7 +33,20 @@ module.exports=t(window)}else{ // like Node. module.exports=t(require("xmldom"),true)}}else{ // Browser globals (root is window) -e.JXON=t(window)}})(this,function(e,t){var r={valueKey:"_",attrKey:"$",attrPrefix:"$",lowerCaseTags:false,trueIsEmpty:false,autoDate:false,ignorePrefixedNodes:false,parseValues:false};var n=[];var i=/^\s*$/;var o=/^(?:true|false)$/i;var a;return new function(){this.config=function(t){for(var n in t){r[n]=t[n]}if(r.parserErrorHandler){a=new e.DOMParser({errorHandler:r.parserErrorHandler,locator:{}})}};function s(e){if(!r.parseValues){return e}if(i.test(e)){return null}if(o.test(e)){return e.toLowerCase()==="true"}if(isFinite(e)){return parseFloat(e)}if(r.autoDate&&isFinite(Date.parse(e))){return new Date(e)}return e}function l(){}l.prototype.toString=function(){return"null"};l.prototype.valueOf=function(){return null};function f(e){return e===null?new l:e instanceof Object?e:new e.constructor(e)}function u(e,t,i,o){var a=4,l=3,c=1,d=n.length,p=e.hasChildNodes(),m=e.nodeType===e.ELEMENT_NODE&&e.hasAttributes(),h=Boolean(t&2),g=0,x="",v=h?{}:/* put here the default value for empty nodes: */r.trueIsEmpty?true:"",w,y;if(p){for(var T,S=0;S0)&&x){v[r.valueKey]=b}else if(!h&&g===0&&x){v=b}if(i&&(h||g>0)){Object.freeze(v)}n.length=d;return v}function c(e,n,i){var o,a,s;if(i.constructor===String||i.constructor===Number||i.constructor===Boolean){n.appendChild(e.createTextNode(i.toString()));/* verbosity level is 0 or 1 */ -if(i===i.valueOf()){return}}else if(i.constructor===Date){n.appendChild(e.createTextNode(i.toISOString()))}for(var l in i){o=i[l];if(o===null){o={}}if(isFinite(l)||o instanceof Function){continue}/* verbosity level is 0 */ -if(l===r.valueKey){if(o!==null&&o!==true){n.appendChild(e.createTextNode(o.constructor===Date?o.toISOString():String(o)))}}else if(l===r.attrKey){/* verbosity level is 3 */ -for(var f in o){n.setAttribute(f,o[f])}}else if(l===r.attrPrefix+"xmlns"){if(t){n.setAttribute(l.slice(1),o)}}else if(l.charAt(0)===r.attrPrefix){n.setAttribute(l.slice(1),o)}else if(o.constructor===Array){for(var u in o){s=o[u]&&o[u][r.attrPrefix+"xmlns"]||n.namespaceURI;if(s){a=e.createElementNS(s,l)}else{a=e.createElement(l)}c(e,a,o[u]||{});n.appendChild(a)}}else{s=(o||{})[r.attrPrefix+"xmlns"]||n.namespaceURI;if(s){a=e.createElementNS(s,l)}else{a=e.createElement(l)}if(o instanceof Object){c(e,a,o)}else if(o!==null&&o!==true){a.appendChild(e.createTextNode(o.toString()))}else if(!r.trueIsEmpty&&o===true){a.appendChild(e.createTextNode(o.toString()))}n.appendChild(a)}}}this.xmlToJs=this.build=function(e,t,r,n){var i=arguments.length>1&&typeof t==="number"?t&3:1;return u(e,i,r||false,arguments.length>3?n:i===3)};this.jsToXml=this.unbuild=function(t,r,n,i){var o=e.document&&e.document.implementation||new e.DOMImplementation;var a=o.createDocument(r||null,n||"",i||null);c(a,a.documentElement||a,t);return a};this.stringToXml=function(t){if(!a){a=new e.DOMParser}return a.parseFromString(t,"application/xml")};this.xmlToString=function(t){if(typeof t.xml!=="undefined"){return t.xml}else{return(new e.XMLSerializer).serializeToString(t)}};this.stringToJs=function(e){var t=this.stringToXml(e);return this.xmlToJs(t)};this.jsToString=this.stringify=function(e,t,r,n){return this.xmlToString(this.jsToXml(e,t,r,n))};this.each=function(e,t,r){if(e instanceof Array){e.forEach(t,r)}else{[e].forEach(t,r)}}}}); \ No newline at end of file +e.JXON=t(window)}})(this,function(e,t){var r={valueKey:"_",attrKey:"$",attrPrefix:"$",lowerCaseTags:false,trueIsEmpty:false,autoDate:false,ignorePrefixedNodes:false,parseValues:false,sequenceKey:"_sequence"};var n=[];var i=/^\s*$/;var o=/^(?:true|false)$/i;var a;return new function(){this.config=function(t){for(var n in t){r[n]=t[n]}if(r.parserErrorHandler){a=new e.DOMParser({errorHandler:r.parserErrorHandler,locator:{}})}};function s(e){if(!r.parseValues){return e}if(i.test(e)){return null}if(o.test(e)){return e.toLowerCase()==="true"}if(isFinite(e)){return parseFloat(e)}if(r.autoDate&&isFinite(Date.parse(e))){return new Date(e)}return e}function f(){}f.prototype.toString=function(){return"null"};f.prototype.valueOf=function(){return null};function u(e){return e===null?new f:e instanceof Object?e:new e.constructor(e)}function l(e,t,i,o){var a=4,f=3,c=1,d=n.length,p=e.hasChildNodes(),m=e.nodeType===e.ELEMENT_NODE&&e.hasAttributes(),h=Boolean(t&2),g=0,y="",x=h?{}:/* put here the default value for empty nodes: */r.trueIsEmpty?true:"",v,w;if(p){for(var T,O=0;O0)&&y){x[r.valueKey]=S}else if(!h&&g===0&&y){x=S}if(i&&(h||g>0)){Object.freeze(x)}n.length=d;return x}function c(e,n,i){var o,a,s;if(i.constructor===String||i.constructor===Number||i.constructor===Boolean){n.appendChild(e.createTextNode(i.toString()));/* verbosity level is 0 or 1 */ +if(i===i.valueOf()){return}}else if(i.constructor===Date){n.appendChild(e.createTextNode(i.toISOString()))} +// Pull out properties names +var f=Object.getOwnPropertyNames(i); +// Look for optional _sequence +if(i.hasOwnProperty(r.sequenceKey)){var u=i[r.sequenceKey]; +// sort prop names based on _sequence +f.sort(function(e,t){ +// Sort comparator +// find index of A and B +var r=u.indexOf(e);var n=u.indexOf(t); +// If prop not named, put on end +if(r<0||n<0){return-1} +// Subtract the indexes +return r-n})}f.forEach(function(f,u){o=i[f];if(o===undefined){return}if(o===null){o={}}if(f===r.sequenceKey){return}if(isFinite(f)||o instanceof Function){return}/* verbosity level is 0 */ +if(f===r.valueKey){if(o!==null&&o!==true){n.appendChild(e.createTextNode(o.constructor===Date?o.toISOString():String(o)))}}else if(f===r.attrKey){/* verbosity level is 3 */ +for(var l in o){n.setAttribute(l,o[l])}}else if(f===r.attrPrefix+"xmlns"){if(t){n.setAttribute(f.slice(1),o)}}else if(f.charAt(0)===r.attrPrefix){n.setAttribute(f.slice(1),o)}else if(o.constructor===Array){for(var d in o){s=o[d]&&o[d][r.attrPrefix+"xmlns"]||n.namespaceURI;if(s){a=e.createElementNS(s,f)}else{a=e.createElement(f)}c(e,a,o[d]||{});n.appendChild(a)}}else{s=(o||{})[r.attrPrefix+"xmlns"]||n.namespaceURI;if(s){a=e.createElementNS(s,f)}else{a=e.createElement(f)}if(o instanceof Object){c(e,a,o)}else if(o!==null&&o!==true){a.appendChild(e.createTextNode(o.toString()))}else if(!r.trueIsEmpty&&o===true){a.appendChild(e.createTextNode(o.toString()))}n.appendChild(a)}})}this.xmlToJs=this.build=function(e,t,r,n){var i=arguments.length>1&&typeof t==="number"?t&3:/* put here the default verbosity level: */1;return l(e,i,r||false,arguments.length>3?n:i===3)};this.jsToXml=this.unbuild=function(t,r,n,i){var o=e.document&&e.document.implementation||new e.DOMImplementation;var a=o.createDocument(r||null,n||"",i||null);c(a,a.documentElement||a,t);return a};this.stringToXml=function(t){if(!a){a=new e.DOMParser}return a.parseFromString(t,"application/xml")};this.xmlToString=function(t){if(typeof t.xml!=="undefined"){return t.xml}else{return(new e.XMLSerializer).serializeToString(t)}};this.stringToJs=function(e){var t=this.stringToXml(e);return this.xmlToJs(t)};this.jsToString=this.stringify=function(e,t,r,n){return this.xmlToString(this.jsToXml(e,t,r,n))};this.each=function(e,t,r){if(e instanceof Array){e.forEach(t,r)}else{[e].forEach(t,r)}}}}); \ No newline at end of file