5ff7e5787d90eff85218ba55a3301ee4c49d4f8f
[ccsdk/apps.git] / sdnr / wireless-transport / code-Carbon-SR1 / ux / mwtnCommons / mwtnCommons-module / src / main / resources / mwtnCommons / xml2json.js
1 /*\r
2  Copyright 2011-2013 Abdulla Abdurakhmanov\r
3  Original sources are available at https://code.google.com/p/x2js/\r
4 \r
5  Licensed under the Apache License, Version 2.0 (the "License");\r
6  you may not use this file except in compliance with the License.\r
7  You may obtain a copy of the License at\r
8 \r
9  http://www.apache.org/licenses/LICENSE-2.0\r
10 \r
11  Unless required by applicable law or agreed to in writing, software\r
12  distributed under the License is distributed on an "AS IS" BASIS,\r
13  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
14  See the License for the specific language governing permissions and\r
15  limitations under the License.\r
16  */\r
17 \r
18 function X2JS(config) {\r
19         'use strict';\r
20                 \r
21         var VERSION = "1.1.5";\r
22         \r
23         config = config || {};\r
24         initConfigDefaults();\r
25         initRequiredPolyfills();\r
26         \r
27         function initConfigDefaults() {\r
28                 if(config.escapeMode === undefined) {\r
29                         config.escapeMode = true;\r
30                 }\r
31                 config.attributePrefix = config.attributePrefix || "_";\r
32                 config.arrayAccessForm = config.arrayAccessForm || "none";\r
33                 config.emptyNodeForm = config.emptyNodeForm || "text";\r
34                 if(config.enableToStringFunc === undefined) {\r
35                         config.enableToStringFunc = true; \r
36                 }\r
37                 config.arrayAccessFormPaths = config.arrayAccessFormPaths || []; \r
38                 if(config.skipEmptyTextNodesForObj === undefined) {\r
39                         config.skipEmptyTextNodesForObj = true;\r
40                 }\r
41                 if(config.stripWhitespaces === undefined) {\r
42                         config.stripWhitespaces = true;\r
43                 }\r
44                 config.datetimeAccessFormPaths = config.datetimeAccessFormPaths || [];\r
45         }\r
46 \r
47         var DOMNodeTypes = {\r
48                 ELEMENT_NODE       : 1,\r
49                 TEXT_NODE          : 3,\r
50                 CDATA_SECTION_NODE : 4,\r
51                 COMMENT_NODE       : 8,\r
52                 DOCUMENT_NODE      : 9\r
53         };\r
54         \r
55         function initRequiredPolyfills() {\r
56                 function pad(number) {\r
57               var r = String(number);\r
58               if ( r.length === 1 ) {\r
59                 r = '0' + r;\r
60               }\r
61               return r;\r
62             }\r
63                 // Hello IE8-\r
64                 if(typeof String.prototype.trim !== 'function') {                       \r
65                         String.prototype.trim = function() {\r
66                                 return this.replace(/^\s+|^\n+|(\s|\n)+$/g, '');\r
67                         }\r
68                 }\r
69                 if(typeof Date.prototype.toISOString !== 'function') {\r
70                         // Implementation from http://stackoverflow.com/questions/2573521/how-do-i-output-an-iso-8601-formatted-string-in-javascript\r
71                         Date.prototype.toISOString = function() {\r
72                       return this.getUTCFullYear()\r
73                         + '-' + pad( this.getUTCMonth() + 1 )\r
74                         + '-' + pad( this.getUTCDate() )\r
75                         + 'T' + pad( this.getUTCHours() )\r
76                         + ':' + pad( this.getUTCMinutes() )\r
77                         + ':' + pad( this.getUTCSeconds() )\r
78                         + '.' + String( (this.getUTCMilliseconds()/1000).toFixed(3) ).slice( 2, 5 )\r
79                         + 'Z';\r
80                     };\r
81                 }\r
82         }\r
83         \r
84         function getNodeLocalName( node ) {\r
85                 var nodeLocalName = node.localName;                     \r
86                 if(nodeLocalName == null) // Yeah, this is IE!! \r
87                         nodeLocalName = node.baseName;\r
88                 if(nodeLocalName == null || nodeLocalName=="") // =="" is IE too\r
89                         nodeLocalName = node.nodeName;\r
90                 return nodeLocalName;\r
91         }\r
92         \r
93         function getNodePrefix(node) {\r
94                 return node.prefix;\r
95         }\r
96                 \r
97         function escapeXmlChars(str) {\r
98                 if(typeof(str) == "string")\r
99                         return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#x27;').replace(/\//g, '&#x2F;');\r
100                 else\r
101                         return str;\r
102         }\r
103 \r
104         function unescapeXmlChars(str) {\r
105                 return str.replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"').replace(/&#x27;/g, "'").replace(/&#x2F;/g, '\/');\r
106         }\r
107         \r
108         function toArrayAccessForm(obj, childName, path) {\r
109                 switch(config.arrayAccessForm) {\r
110                 case "property":\r
111                         if(!(obj[childName] instanceof Array))\r
112                                 obj[childName+"_asArray"] = [obj[childName]];\r
113                         else\r
114                                 obj[childName+"_asArray"] = obj[childName];\r
115                         break;          \r
116                 /*case "none":\r
117                         break;*/\r
118                 }\r
119                 \r
120                 if(!(obj[childName] instanceof Array) && config.arrayAccessFormPaths.length > 0) {\r
121                         var idx = 0;\r
122                         for(; idx < config.arrayAccessFormPaths.length; idx++) {\r
123                                 var arrayPath = config.arrayAccessFormPaths[idx];\r
124                                 if( typeof arrayPath === "string" ) {\r
125                                         if(arrayPath == path)\r
126                                                 break;\r
127                                 }\r
128                                 else\r
129                                 if( arrayPath instanceof RegExp) {\r
130                                         if(arrayPath.test(path))\r
131                                                 break;\r
132                                 }                               \r
133                                 else\r
134                                 if( typeof arrayPath === "function") {\r
135                                         if(arrayPath(obj, childName, path))\r
136                                                 break;\r
137                                 }\r
138                         }\r
139                         if(idx!=config.arrayAccessFormPaths.length) {\r
140                                 obj[childName] = [obj[childName]];\r
141                         }\r
142                 }\r
143         }\r
144         \r
145         function fromXmlDateTime(prop) {\r
146                 // Implementation based up on http://stackoverflow.com/questions/8178598/xml-datetime-to-javascript-date-object\r
147                 // Improved to support full spec and optional parts\r
148                 var bits = prop.split(/[-T:+Z]/g);\r
149                 \r
150                 var d = new Date(bits[0], bits[1]-1, bits[2]);                  \r
151                 var secondBits = bits[5].split("\.");\r
152                 d.setHours(bits[3], bits[4], secondBits[0]);\r
153                 if(secondBits.length>1)\r
154                         d.setMilliseconds(secondBits[1]);\r
155 \r
156                 // Get supplied time zone offset in minutes\r
157                 if(bits[6] && bits[7]) {\r
158                         var offsetMinutes = bits[6] * 60 + Number(bits[7]);\r
159                         var sign = /\d\d-\d\d:\d\d$/.test(prop)? '-' : '+';\r
160 \r
161                         // Apply the sign\r
162                         offsetMinutes = 0 + (sign == '-'? -1 * offsetMinutes : offsetMinutes);\r
163 \r
164                         // Apply offset and local timezone\r
165                         d.setMinutes(d.getMinutes() - offsetMinutes - d.getTimezoneOffset())\r
166                 }\r
167                 else\r
168                         if(prop.indexOf("Z", prop.length - 1) !== -1) {\r
169                                 d = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds()));                                  \r
170                         }\r
171 \r
172                 // d is now a local time equivalent to the supplied time\r
173                 return d;\r
174         }\r
175         \r
176         function checkFromXmlDateTimePaths(value, childName, fullPath) {\r
177                 if(config.datetimeAccessFormPaths.length > 0) {\r
178                         var path = fullPath.split("\.#")[0];\r
179                         var idx = 0;\r
180                         for(; idx < config.datetimeAccessFormPaths.length; idx++) {\r
181                                 var dtPath = config.datetimeAccessFormPaths[idx];\r
182                                 if( typeof dtPath === "string" ) {\r
183                                         if(dtPath == path)\r
184                                                 break;\r
185                                 }\r
186                                 else\r
187                                 if( dtPath instanceof RegExp) {\r
188                                         if(dtPath.test(path))\r
189                                                 break;\r
190                                 }                               \r
191                                 else\r
192                                 if( typeof dtPath === "function") {\r
193                                         if(dtPath(obj, childName, path))\r
194                                                 break;\r
195                                 }\r
196                         }\r
197                         if(idx!=config.datetimeAccessFormPaths.length) {\r
198                                 return fromXmlDateTime(value);\r
199                         }\r
200                         else\r
201                                 return value;\r
202                 }\r
203                 else\r
204                         return value;\r
205         }\r
206 \r
207         function parseDOMChildren( node, path ) {\r
208                 if(node.nodeType == DOMNodeTypes.DOCUMENT_NODE) {\r
209                         var result = new Object;\r
210                         var nodeChildren = node.childNodes;\r
211                         // Alternative for firstElementChild which is not supported in some environments\r
212                         for(var cidx=0; cidx <nodeChildren.length; cidx++) {\r
213                                 var child = nodeChildren.item(cidx);\r
214                                 if(child.nodeType == DOMNodeTypes.ELEMENT_NODE) {\r
215                                         var childName = getNodeLocalName(child);\r
216                                         result[childName] = parseDOMChildren(child, childName);\r
217                                 }\r
218                         }\r
219                         return result;\r
220                 }\r
221                 else\r
222                 if(node.nodeType == DOMNodeTypes.ELEMENT_NODE) {\r
223                         var result = new Object;\r
224                         result.__cnt=0;\r
225                         \r
226                         var nodeChildren = node.childNodes;\r
227                         \r
228                         // Children nodes\r
229                         for(var cidx=0; cidx <nodeChildren.length; cidx++) {\r
230                                 var child = nodeChildren.item(cidx); // nodeChildren[cidx];\r
231                                 var childName = getNodeLocalName(child);\r
232                                 \r
233                                 if(child.nodeType!= DOMNodeTypes.COMMENT_NODE) {\r
234                                         result.__cnt++;\r
235                                         if(result[childName] == null) {\r
236                                                 result[childName] = parseDOMChildren(child, path+"."+childName);\r
237                                                 toArrayAccessForm(result, childName, path+"."+childName);                                       \r
238                                         }\r
239                                         else {\r
240                                                 if(result[childName] != null) {\r
241                                                         if( !(result[childName] instanceof Array)) {\r
242                                                                 result[childName] = [result[childName]];\r
243                                                                 toArrayAccessForm(result, childName, path+"."+childName);\r
244                                                         }\r
245                                                 }\r
246                                                 (result[childName])[result[childName].length] = parseDOMChildren(child, path+"."+childName);\r
247                                         }\r
248                                 }                                                               \r
249                         }\r
250                         \r
251                         // Attributes\r
252                         for(var aidx=0; aidx <node.attributes.length; aidx++) {\r
253                                 var attr = node.attributes.item(aidx); // [aidx];\r
254                                 result.__cnt++;\r
255                                 result[config.attributePrefix+attr.name]=attr.value;\r
256                         }\r
257                         \r
258                         // Node namespace prefix\r
259                         var nodePrefix = getNodePrefix(node);\r
260                         if(nodePrefix!=null && nodePrefix!="") {\r
261                                 result.__cnt++;\r
262                                 result.__prefix=nodePrefix;\r
263                         }\r
264                         \r
265                         if(result["#text"]!=null) {                             \r
266                                 result.__text = result["#text"];\r
267                                 if(result.__text instanceof Array) {\r
268                                         result.__text = result.__text.join("\n");\r
269                                 }\r
270                                 if(config.escapeMode)\r
271                                         result.__text = unescapeXmlChars(result.__text);\r
272                                 if(config.stripWhitespaces)\r
273                                         result.__text = result.__text.trim();\r
274                                 delete result["#text"];\r
275                                 if(config.arrayAccessForm=="property")\r
276                                         delete result["#text_asArray"];\r
277                                 result.__text = checkFromXmlDateTimePaths(result.__text, childName, path+"."+childName);\r
278                         }\r
279                         if(result["#cdata-section"]!=null) {\r
280                                 result.__cdata = result["#cdata-section"];\r
281                                 delete result["#cdata-section"];\r
282                                 if(config.arrayAccessForm=="property")\r
283                                         delete result["#cdata-section_asArray"];\r
284                         }\r
285                         \r
286                         if( result.__cnt == 1 && result.__text!=null  ) {\r
287                                 result = result.__text;\r
288                         }\r
289                         else\r
290                         if( result.__cnt == 0 && config.emptyNodeForm=="text" ) {\r
291                                 result = '';\r
292                         }\r
293                         else\r
294                         if ( result.__cnt > 1 && result.__text!=null && config.skipEmptyTextNodesForObj) {\r
295                                 if( (config.stripWhitespaces && result.__text=="") || (result.__text.trim()=="")) {\r
296                                         delete result.__text;\r
297                                 }\r
298                         }\r
299                         delete result.__cnt;                    \r
300                         \r
301                         if( config.enableToStringFunc && (result.__text!=null || result.__cdata!=null )) {\r
302                                 result.toString = function() {\r
303                                         return (this.__text!=null? this.__text:'')+( this.__cdata!=null ? this.__cdata:'');\r
304                                 };\r
305                         }\r
306                         \r
307                         return result;\r
308                 }\r
309                 else\r
310                 if(node.nodeType == DOMNodeTypes.TEXT_NODE || node.nodeType == DOMNodeTypes.CDATA_SECTION_NODE) {\r
311                         return node.nodeValue;\r
312                 }       \r
313         }\r
314         \r
315         function startTag(jsonObj, element, attrList, closed) {\r
316                 var resultStr = "<"+ ( (jsonObj!=null && jsonObj.__prefix!=null)? (jsonObj.__prefix+":"):"") + element;\r
317                 if(attrList!=null) {\r
318                         for(var aidx = 0; aidx < attrList.length; aidx++) {\r
319                                 var attrName = attrList[aidx];\r
320                                 var attrVal = jsonObj[attrName];\r
321                                 if(config.escapeMode)\r
322                                         attrVal=escapeXmlChars(attrVal);\r
323                                 resultStr+=" "+attrName.substr(config.attributePrefix.length)+"='"+attrVal+"'";\r
324                         }\r
325                 }\r
326                 if(!closed)\r
327                         resultStr+=">";\r
328                 else\r
329                         resultStr+="/>";\r
330                 return resultStr;\r
331         }\r
332         \r
333         function endTag(jsonObj,elementName) {\r
334                 return "</"+ (jsonObj.__prefix!=null? (jsonObj.__prefix+":"):"")+elementName+">";\r
335         }\r
336         \r
337         function endsWith(str, suffix) {\r
338             return str.indexOf(suffix, str.length - suffix.length) !== -1;\r
339         }\r
340         \r
341         function jsonXmlSpecialElem ( jsonObj, jsonObjField ) {\r
342                 if((config.arrayAccessForm=="property" && endsWith(jsonObjField.toString(),("_asArray"))) \r
343                                 || jsonObjField.toString().indexOf(config.attributePrefix)==0 \r
344                                 || jsonObjField.toString().indexOf("__")==0\r
345                                 || (jsonObj[jsonObjField] instanceof Function) )\r
346                         return true;\r
347                 else\r
348                         return false;\r
349         }\r
350         \r
351         function jsonXmlElemCount ( jsonObj ) {\r
352                 var elementsCnt = 0;\r
353                 if(jsonObj instanceof Object ) {\r
354                         for( var it in jsonObj  ) {\r
355                                 if(jsonXmlSpecialElem ( jsonObj, it) )\r
356                                         continue;                       \r
357                                 elementsCnt++;\r
358                         }\r
359                 }\r
360                 return elementsCnt;\r
361         }\r
362         \r
363         function parseJSONAttributes ( jsonObj ) {\r
364                 var attrList = [];\r
365                 if(jsonObj instanceof Object ) {\r
366                         for( var ait in jsonObj  ) {\r
367                                 if(ait.toString().indexOf("__")== -1 && ait.toString().indexOf(config.attributePrefix)==0) {\r
368                                         attrList.push(ait);\r
369                                 }\r
370                         }\r
371                 }\r
372                 return attrList;\r
373         }\r
374         \r
375         function parseJSONTextAttrs ( jsonTxtObj ) {\r
376                 var result ="";\r
377                 \r
378                 if(jsonTxtObj.__cdata!=null) {                                                                          \r
379                         result+="<![CDATA["+jsonTxtObj.__cdata+"]]>";                                   \r
380                 }\r
381                 \r
382                 if(jsonTxtObj.__text!=null) {                   \r
383                         if(config.escapeMode)\r
384                                 result+=escapeXmlChars(jsonTxtObj.__text);\r
385                         else\r
386                                 result+=jsonTxtObj.__text;\r
387                 }\r
388                 return result;\r
389         }\r
390         \r
391         function parseJSONTextObject ( jsonTxtObj ) {\r
392                 var result ="";\r
393 \r
394                 if( jsonTxtObj instanceof Object ) {\r
395                         result+=parseJSONTextAttrs ( jsonTxtObj );\r
396                 }\r
397                 else\r
398                         if(jsonTxtObj!=null) {\r
399                                 if(config.escapeMode)\r
400                                         result+=escapeXmlChars(jsonTxtObj);\r
401                                 else\r
402                                         result+=jsonTxtObj;\r
403                         }\r
404                 \r
405                 return result;\r
406         }\r
407         \r
408         function parseJSONArray ( jsonArrRoot, jsonArrObj, attrList ) {\r
409                 var result = ""; \r
410                 if(jsonArrRoot.length == 0) {\r
411                         result+=startTag(jsonArrRoot, jsonArrObj, attrList, true);\r
412                 }\r
413                 else {\r
414                         for(var arIdx = 0; arIdx < jsonArrRoot.length; arIdx++) {\r
415                                 result+=startTag(jsonArrRoot[arIdx], jsonArrObj, parseJSONAttributes(jsonArrRoot[arIdx]), false);\r
416                                 result+=parseJSONObject(jsonArrRoot[arIdx]);\r
417                                 result+=endTag(jsonArrRoot[arIdx],jsonArrObj);                                          \r
418                         }\r
419                 }\r
420                 return result;\r
421         }\r
422         \r
423         function parseJSONObject ( jsonObj ) {\r
424                 var result = "";        \r
425 \r
426                 var elementsCnt = jsonXmlElemCount ( jsonObj );\r
427                 \r
428                 if(elementsCnt > 0) {\r
429                         for( var it in jsonObj ) {\r
430                                 \r
431                                 if(jsonXmlSpecialElem ( jsonObj, it) )\r
432                                         continue;                       \r
433                                 \r
434                                 var subObj = jsonObj[it];                                               \r
435                                 \r
436                                 var attrList = parseJSONAttributes( subObj )\r
437                                 \r
438                                 if(subObj == null || subObj == undefined) {\r
439                                         result+=startTag(subObj, it, attrList, true);\r
440                                 }\r
441                                 else\r
442                                 if(subObj instanceof Object) {\r
443                                         \r
444                                         if(subObj instanceof Array) {                                   \r
445                                                 result+=parseJSONArray( subObj, it, attrList );                                 \r
446                                         }\r
447                                         else if(subObj instanceof Date) {\r
448                                                 result+=startTag(subObj, it, attrList, false);\r
449                                                 result+=subObj.toISOString();\r
450                                                 result+=endTag(subObj,it);\r
451                                         }\r
452                                         else {\r
453                                                 var subObjElementsCnt = jsonXmlElemCount ( subObj );\r
454                                                 if(subObjElementsCnt > 0 || subObj.__text!=null || subObj.__cdata!=null) {\r
455                                                         result+=startTag(subObj, it, attrList, false);\r
456                                                         result+=parseJSONObject(subObj);\r
457                                                         result+=endTag(subObj,it);\r
458                                                 }\r
459                                                 else {\r
460                                                         result+=startTag(subObj, it, attrList, true);\r
461                                                 }\r
462                                         }\r
463                                 }\r
464                                 else {\r
465                                         result+=startTag(subObj, it, attrList, false);\r
466                                         result+=parseJSONTextObject(subObj);\r
467                                         result+=endTag(subObj,it);\r
468                                 }\r
469                         }\r
470                 }\r
471                 result+=parseJSONTextObject(jsonObj);\r
472                 \r
473                 return result;\r
474         }\r
475         \r
476         this.parseXmlString = function(xmlDocStr) {\r
477                 var isIEParser = window.ActiveXObject || "ActiveXObject" in window;\r
478                 if (xmlDocStr === undefined) {\r
479                         return null;\r
480                 }\r
481                 var xmlDoc;\r
482                 if (window.DOMParser) {\r
483                         var parser=new window.DOMParser();                      \r
484                         var parsererrorNS = null;\r
485                         // IE9+ now is here\r
486                         if(!isIEParser) {\r
487                                 try {\r
488                                         parsererrorNS = parser.parseFromString("INVALID", "text/xml").childNodes[0].namespaceURI;\r
489                                 }\r
490                                 catch(err) {                                    \r
491                                         parsererrorNS = null;\r
492                                 }\r
493                         }\r
494                         try {\r
495                                 xmlDoc = parser.parseFromString( xmlDocStr, "text/xml" );\r
496                                 if( parsererrorNS!= null && xmlDoc.getElementsByTagNameNS(parsererrorNS, "parsererror").length > 0) {\r
497                                         //throw new Error('Error parsing XML: '+xmlDocStr);\r
498                                         xmlDoc = null;\r
499                                 }\r
500                         }\r
501                         catch(err) {\r
502                                 xmlDoc = null;\r
503                         }\r
504                 }\r
505                 else {\r
506                         // IE :(\r
507                         if(xmlDocStr.indexOf("<?")==0) {\r
508                                 xmlDocStr = xmlDocStr.substr( xmlDocStr.indexOf("?>") + 2 );\r
509                         }\r
510                         xmlDoc=new ActiveXObject("Microsoft.XMLDOM");\r
511                         xmlDoc.async="false";\r
512                         xmlDoc.loadXML(xmlDocStr);\r
513                 }\r
514                 return xmlDoc;\r
515         };\r
516         \r
517         this.asArray = function(prop) {\r
518                 if(prop instanceof Array)\r
519                         return prop;\r
520                 else\r
521                         return [prop];\r
522         };\r
523         \r
524         this.toXmlDateTime = function(dt) {\r
525                 if(dt instanceof Date)\r
526                         return dt.toISOString();\r
527                 else\r
528                 if(typeof(dt) === 'number' )\r
529                         return new Date(dt).toISOString();\r
530                 else    \r
531                         return null;\r
532         };\r
533         \r
534         this.asDateTime = function(prop) {\r
535                 if(typeof(prop) == "string") {\r
536                         return fromXmlDateTime(prop);\r
537                 }\r
538                 else\r
539                         return prop;\r
540         };\r
541 \r
542         this.xml2json = function (xmlDoc) {\r
543                 return parseDOMChildren ( xmlDoc );\r
544         };\r
545         \r
546         this.xml_str2json = function (xmlDocStr) {\r
547                 var xmlDoc = this.parseXmlString(xmlDocStr);\r
548                 if(xmlDoc!=null)\r
549                         return this.xml2json(xmlDoc);\r
550                 else\r
551                         return null;\r
552         };\r
553 \r
554         this.json2xml_str = function (jsonObj) {\r
555                 return parseJSONObject ( jsonObj );\r
556         };\r
557 \r
558         this.json2xml = function (jsonObj) {\r
559                 var xmlDocStr = this.json2xml_str (jsonObj);\r
560                 return this.parseXmlString(xmlDocStr);\r
561         };\r
562         \r
563         this.getVersion = function () {\r
564                 return VERSION;\r
565         };\r
566         \r
567 }\r