corrade-nucleus-nucleons – Blame information for rev 21
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
21 | office | 1 | /*
|
2 | Copyright 2015 Axinom
|
||
3 | Copyright 2011-2013 Abdulla Abdurakhmanov
|
||
4 | Original sources are available at https://code.google.com/p/x2js/
|
||
5 | |||
6 | Licensed under the Apache License, Version 2.0 (the "License");
|
||
7 | you may not use this file except in compliance with the License.
|
||
8 | You may obtain a copy of the License at
|
||
9 | |||
10 | http://www.apache.org/licenses/LICENSE-2.0
|
||
11 | |||
12 | Unless required by applicable law or agreed to in writing, software
|
||
13 | distributed under the License is distributed on an "AS IS" BASIS,
|
||
14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
15 | See the License for the specific language governing permissions and
|
||
16 | limitations under the License.
|
||
17 | */ |
||
18 | |||
19 | /*
|
||
20 | Supported export methods:
|
||
21 | * AMD
|
||
22 | * <script> (window.X2JS)
|
||
23 | * Node.js
|
||
24 | |||
25 | Limitations:
|
||
26 | * Attribute namespace prefixes are not parsed as such.
|
||
27 | * Overall the serialization/deserializaton code is "best effort" and not foolproof.
|
||
28 | */ |
||
29 | |||
30 | // Module definition pattern used is returnExports from https://github.com/umdjs/umd
|
||
31 | (function (root, factory) { |
||
32 | "use strict"; |
||
33 | |||
34 | /* global define */ |
||
35 | if (typeof define === 'function' && define.amd) { |
||
36 | // AMD. Register as an anonymous module.
|
||
37 | define([], factory); |
||
38 | } else if (typeof module === 'object' && module.exports) { |
||
39 | // Node. Does not work with strict CommonJS, but only CommonJS-like
|
||
40 | // environments that support module.exports, like Node.
|
||
41 | module.exports = factory(require("xmldom").DOMParser); |
||
42 | } else { |
||
43 | // Browser globals (root is window)
|
||
44 | root.X2JS = factory(); |
||
45 | } |
||
46 | })(this, function (CustomDOMParser) { |
||
47 | "use strict"; |
||
48 | |||
49 | // We return a constructor that can be used to make X2JS instances.
|
||
50 | return function X2JS(config) { |
||
51 | var VERSION = "3.1.1"; |
||
52 | |||
53 | config = config || {}; |
||
54 | |||
55 | function initConfigDefaults() { |
||
56 | // If set to "property" then <element>_asArray will be created
|
||
57 | // to allow you to access any element as an array (even if there is only one of it).
|
||
58 | config.arrayAccessForm = config.arrayAccessForm || "none"; |
||
59 | |||
60 | // If "text" then <empty></empty> will be transformed to "".
|
||
61 | // If "object" then <empty></empty> will be transformed to {}.
|
||
62 | config.emptyNodeForm = config.emptyNodeForm || "text"; |
||
63 | |||
64 | // Allows attribute values to be converted on the fly during parsing to objects.
|
||
65 | // "test": function(name, value) { return true; }
|
||
66 | // "convert": function(name, value) { return parseFloat(value);
|
||
67 | // convert() will be called for every attribute where test() returns true
|
||
68 | // and the return value from convert() will replace the original value of the attribute.
|
||
69 | config.attributeConverters = config.attributeConverters || []; |
||
70 | |||
71 | // Any elements that match the paths here will have their text parsed
|
||
72 | // as an XML datetime value (2011-11-12T13:00:00-07:00 style).
|
||
73 | // The path can be a plain string (parent.child1.child2),
|
||
74 | // a regex (/.*\.child2/) or function(elementPath).
|
||
75 | config.datetimeAccessFormPaths = config.datetimeAccessFormPaths || []; |
||
76 | |||
77 | // Any elements that match the paths listed here will be stored in JavaScript objects
|
||
78 | // as arrays even if there is only one of them. The path can be a plain string
|
||
79 | // (parent.child1.child2), a regex (/.*\.child2/) or function(elementName, elementPath).
|
||
80 | config.arrayAccessFormPaths = config.arrayAccessFormPaths || []; |
||
81 | |||
82 | // If true, a toString function is generated to print nodes containing text or cdata.
|
||
83 | // Useful if you want to accept both plain text and CData as equivalent inputs.
|
||
84 | if (config.enableToStringFunc === undefined) { |
||
85 | config.enableToStringFunc = true; |
||
86 | } |
||
87 | |||
88 | // If true, empty text tags are ignored for elements with child nodes.
|
||
89 | if (config.skipEmptyTextNodesForObj === undefined) { |
||
90 | config.skipEmptyTextNodesForObj = true; |
||
91 | } |
||
92 | |||
93 | // If true, whitespace is trimmed from text nodes.
|
||
94 | if (config.stripWhitespaces === undefined) { |
||
95 | config.stripWhitespaces = true; |
||
96 | } |
||
97 | |||
98 | // If true, double quotes are used in generated XML.
|
||
99 | if (config.useDoubleQuotes === undefined) { |
||
100 | config.useDoubleQuotes = true; |
||
101 | } |
||
102 | |||
103 | // If true, the root element of the XML document is ignored when converting to objects.
|
||
104 | // The result will directly have the root element's children as its own properties.
|
||
105 | if (config.ignoreRoot === undefined) { |
||
106 | config.ignoreRoot = false; |
||
107 | } |
||
108 | |||
109 | // Whether XML characters in text are escaped when reading/writing XML.
|
||
110 | if (config.escapeMode === undefined) { |
||
111 | config.escapeMode = true; |
||
112 | } |
||
113 | |||
114 | // Prefix to use for properties that are created to represent XML attributes.
|
||
115 | if (config.attributePrefix === undefined) { |
||
116 | config.attributePrefix = "_"; |
||
117 | } |
||
118 | |||
119 | // If true, empty elements will created as self closing elements (<element />)
|
||
120 | // If false, empty elements will be created with start and end tags (<element></element>)
|
||
121 | if (config.selfClosingElements === undefined) { |
||
122 | config.selfClosingElements = true; |
||
123 | } |
||
124 | |||
125 | // If this property defined as false and an XML element has CData node ONLY, it will be converted to text without additional property "__cdata"
|
||
126 | if (config.keepCData === undefined) { |
||
127 | config.keepCData = false; |
||
128 | } |
||
129 | } |
||
130 | |||
131 | function initRequiredPolyfills() { |
||
132 | function pad(number) { |
||
133 | var r = String(number); |
||
134 | if (r.length === 1) { |
||
135 | r = '0' + r; |
||
136 | } |
||
137 | return r; |
||
138 | } |
||
139 | // Hello IE8-
|
||
140 | if (typeof String.prototype.trim !== 'function') { |
||
141 | String.prototype.trim = function trim() { |
||
142 | return this.replace(/^\s+|^\n+|(\s|\n)+$/g, ''); |
||
143 | }; |
||
144 | } |
||
145 | if (typeof Date.prototype.toISOString !== 'function') { |
||
146 | // Implementation from http://stackoverflow.com/questions/2573521/how-do-i-output-an-iso-8601-formatted-string-in-javascript
|
||
147 | Date.prototype.toISOString = function toISOString() { |
||
148 | var MS_IN_S = 1000; |
||
149 | |||
150 | return this.getUTCFullYear() |
||
151 | + '-' + pad(this.getUTCMonth() + 1) |
||
152 | + '-' + pad(this.getUTCDate()) |
||
153 | + 'T' + pad(this.getUTCHours()) |
||
154 | + ':' + pad(this.getUTCMinutes()) |
||
155 | + ':' + pad(this.getUTCSeconds()) |
||
156 | + '.' + String((this.getUTCMilliseconds() / MS_IN_S).toFixed(3)).slice(2, 5)
|
||
157 | + 'Z';
|
||
158 | };
|
||
159 | }
|
||
160 | }
|
||
161 | |||
162 | initConfigDefaults();
|
||
163 | initRequiredPolyfills();
|
||
164 | |||
165 | var DOMNodeTypes = {
|
||
166 | "ELEMENT_NODE": 1,
|
||
167 | "TEXT_NODE": 3,
|
||
168 | "CDATA_SECTION_NODE": 4,
|
||
169 | "COMMENT_NODE": 8,
|
||
170 | "DOCUMENT_NODE": 9
|
||
171 | };
|
||
172 | |||
173 | function getDomNodeLocalName(domNode) {
|
||
174 | var localName = domNode.localName;
|
||
175 | if (localName == null) {
|
||
176 | // Yeah, this is IE!!
|
||
177 | localName = domNode.baseName;
|
||
178 | }
|
||
179 | if (localName == null || localName === "") {
|
||
180 | // ==="" is IE too
|
||
181 | localName = domNode.nodeName;
|
||
182 | }
|
||
183 | return localName;
|
||
184 | }
|
||
185 | |||
186 | function getDomNodeNamespacePrefix(node) {
|
||
187 | return node.prefix;
|
||
188 | }
|
||
189 | |||
190 | function escapeXmlChars(str) {
|
||
191 | if (typeof str === "string")
|
||
192 | return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''');
|
||
193 | else
|
||
194 | return str;
|
||
195 | }
|
||
196 | |||
197 | function unescapeXmlChars(str) {
|
||
198 | return str.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, "'").replace(/&/g, '&');
|
||
199 | }
|
||
200 | |||
201 | function ensureProperArrayAccessForm(element, childName, elementPath) {
|
||
202 | switch (config.arrayAccessForm) {
|
||
203 | case "property":
|
||
204 | if (!(element[childName] instanceof Array))
|
||
205 | element[childName + "_asArray"] = [element[childName]];
|
||
206 | else
|
||
207 | element[childName + "_asArray"] = element[childName];
|
||
208 | break;
|
||
209 | }
|
||
210 | |||
211 | if (!(element[childName] instanceof Array) && config.arrayAccessFormPaths.length > 0) {
|
||
212 | var match = false;
|
||
213 | |||
214 | for (var i = 0; i < config.arrayAccessFormPaths.length; i++) {
|
||
215 | var arrayPath = config.arrayAccessFormPaths[i];
|
||
216 | if (typeof arrayPath === "string") {
|
||
217 | if (arrayPath === elementPath) {
|
||
218 | match = true;
|
||
219 | break;
|
||
220 | }
|
||
221 | } else if (arrayPath instanceof RegExp) {
|
||
222 | if (arrayPath.test(elementPath)) {
|
||
223 | match = true;
|
||
224 | break;
|
||
225 | }
|
||
226 | } else if (typeof arrayPath === "function") {
|
||
227 | if (arrayPath(childName, elementPath)) {
|
||
228 | match = true;
|
||
229 | break;
|
||
230 | }
|
||
231 | }
|
||
232 | }
|
||
233 | |||
234 | if (match)
|
||
235 | element[childName] = [element[childName]];
|
||
236 | }
|
||
237 | }
|
||
238 | |||
239 | function xmlDateTimeToDate(prop) {
|
||
240 | // Implementation based up on http://stackoverflow.com/questions/8178598/xml-datetime-to-javascript-date-object
|
||
241 | // Improved to support full spec and optional parts
|
||
242 | var MINUTES_PER_HOUR = 60;
|
||
243 | |||
244 | var bits = prop.split(/[-T:+Z]/g);
|
||
245 | |||
246 | var d = new Date(bits[0], bits[1] - 1, bits[2]);
|
||
247 | var secondBits = bits[5].split("\.");
|
||
248 | d.setHours(bits[3], bits[4], secondBits[0]);
|
||
249 | if (secondBits.length > 1)
|
||
250 | d.setMilliseconds(secondBits[1]);
|
||
251 | |||
252 | // Get supplied time zone offset in minutes
|
||
253 | if (bits[6] && bits[7]) {
|
||
254 | var offsetMinutes = bits[6] * MINUTES_PER_HOUR + Number(bits[7]);
|
||
255 | var sign = /\d\d-\d\d:\d\d$/.test(prop) ? '-' : '+';
|
||
256 | |||
257 | // Apply the sign
|
||
258 | offsetMinutes = 0 + (sign === '-' ? -1 * offsetMinutes : offsetMinutes);
|
||
259 | |||
260 | // Apply offset and local timezone
|
||
261 | d.setMinutes(d.getMinutes() - offsetMinutes - d.getTimezoneOffset());
|
||
262 | } else if (prop.indexOf("Z", prop.length - 1) !== -1) {
|
||
263 | d = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds()));
|
||
264 | }
|
||
265 | |||
266 | // d is now a local time equivalent to the supplied time
|
||
267 | return d;
|
||
268 | }
|
||
269 | |||
270 | function convertToDateIfRequired(value, childName, fullPath) {
|
||
271 | if (config.datetimeAccessFormPaths.length > 0) {
|
||
272 | var pathWithoutTextNode = fullPath.split("\.#")[0];
|
||
273 | |||
274 | for (var i = 0; i < config.datetimeAccessFormPaths.length; i++) {
|
||
275 | var candidatePath = config.datetimeAccessFormPaths[i];
|
||
276 | if (typeof candidatePath === "string") {
|
||
277 | if (candidatePath === pathWithoutTextNode)
|
||
278 | return xmlDateTimeToDate(value);
|
||
279 | } else if (candidatePath instanceof RegExp) {
|
||
280 | if (candidatePath.test(pathWithoutTextNode))
|
||
281 | return xmlDateTimeToDate(value);
|
||
282 | } else if (typeof candidatePath === "function") {
|
||
283 | if (candidatePath(pathWithoutTextNode))
|
||
284 | return xmlDateTimeToDate(value);
|
||
285 | }
|
||
286 | }
|
||
287 | }
|
||
288 | |||
289 | return value;
|
||
290 | }
|
||
291 | |||
292 | function deserializeRootElementChildren(rootElement) {
|
||
293 | var result = {};
|
||
294 | var children = rootElement.childNodes;
|
||
295 | |||
296 | // Alternative for firstElementChild which is not supported in some environments
|
||
297 | for (var i = 0; i < children.length; i++) {
|
||
298 | var child = children.item(i);
|
||
299 | if (child.nodeType === DOMNodeTypes.ELEMENT_NODE) {
|
||
300 | var childName = getDomNodeLocalName(child);
|
||
301 | |||
302 | if (config.ignoreRoot)
|
||
303 | result = deserializeDomChildren(child, childName);
|
||
304 | else
|
||
305 | result[childName] = deserializeDomChildren(child, childName);
|
||
306 | }
|
||
307 | }
|
||
308 | |||
309 | return result;
|
||
310 | }
|
||
311 | |||
312 | function deserializeElementChildren(element, elementPath) {
|
||
313 | var result = {};
|
||
314 | result.__cnt = 0;
|
||
315 | |||
316 | var nodeChildren = element.childNodes;
|
||
317 | |||
318 | // Child nodes.
|
||
319 | for (var iChild = 0; iChild < nodeChildren.length; iChild++) {
|
||
320 | var child = nodeChildren.item(iChild);
|
||
321 | var childName = getDomNodeLocalName(child);
|
||
322 | |||
323 | if (child.nodeType === DOMNodeTypes.COMMENT_NODE)
|
||
324 | continue;
|
||
325 | |||
326 | result.__cnt++;
|
||
327 | |||
328 | // We deliberately do not accept everything falsey here because
|
||
329 | // elements that resolve to empty string should still be preserved.
|
||
330 | if (result[childName] == null) {
|
||
331 | result[childName] = deserializeDomChildren(child, elementPath + "." + childName);
|
||
332 | ensureProperArrayAccessForm(result, childName, elementPath + "." + childName);
|
||
333 | } else {
|
||
334 | if (!(result[childName] instanceof Array)) {
|
||
335 | result[childName] = [result[childName]];
|
||
336 | ensureProperArrayAccessForm(result, childName, elementPath + "." + childName);
|
||
337 | }
|
||
338 | |||
339 | result[childName][result[childName].length] = deserializeDomChildren(child, elementPath + "." + childName);
|
||
340 | }
|
||
341 | }
|
||
342 | |||
343 | // Attributes
|
||
344 | for (var iAttribute = 0; iAttribute < element.attributes.length; iAttribute++) {
|
||
345 | var attribute = element.attributes.item(iAttribute);
|
||
346 | result.__cnt++;
|
||
347 | |||
348 | var adjustedValue = attribute.value;
|
||
349 | for (var iConverter = 0; iConverter < config.attributeConverters.length; iConverter++) {
|
||
350 | var converter = config.attributeConverters[iConverter];
|
||
351 | if (converter.test.call(null, attribute.name, attribute.value))
|
||
352 | adjustedValue = converter.convert.call(null, attribute.name, attribute.value);
|
||
353 | }
|
||
354 | |||
355 | result[config.attributePrefix + attribute.name] = adjustedValue;
|
||
356 | }
|
||
357 | |||
358 | // Node namespace prefix
|
||
359 | var namespacePrefix = getDomNodeNamespacePrefix(element);
|
||
360 | if (namespacePrefix) {
|
||
361 | result.__cnt++;
|
||
362 | result.__prefix = namespacePrefix;
|
||
363 | }
|
||
364 | |||
365 | if (result["#text"]) {
|
||
366 | result.__text = result["#text"];
|
||
367 | |||
368 | if (result.__text instanceof Array) {
|
||
369 | result.__text = result.__text.join("\n");
|
||
370 | }
|
||
371 | |||
372 | if (config.escapeMode)
|
||
373 | result.__text = unescapeXmlChars(result.__text);
|
||
374 | |||
375 | if (config.stripWhitespaces)
|
||
376 | result.__text = result.__text.trim();
|
||
377 | |||
378 | delete result["#text"];
|
||
379 | |||
380 | if (config.arrayAccessForm === "property")
|
||
381 | delete result["#text_asArray"];
|
||
382 | |||
383 | result.__text = convertToDateIfRequired(result.__text, "#text", elementPath + ".#text");
|
||
384 | }
|
||
385 | |||
386 | if (result.hasOwnProperty('#cdata-section')) {
|
||
387 | result.__cdata = result["#cdata-section"];
|
||
388 | delete result["#cdata-section"];
|
||
389 | |||
390 | if (config.arrayAccessForm === "property")
|
||
391 | delete result["#cdata-section_asArray"];
|
||
392 | }
|
||
393 | |||
394 | if (result.__cnt === 1 && result.__text) {
|
||
395 | result = result.__text;
|
||
396 | } else if (result.__cnt === 0 && config.emptyNodeForm === "text") {
|
||
397 | result = '';
|
||
398 | } else if (result.__cnt > 1 && result.__text !== undefined && config.skipEmptyTextNodesForObj) {
|
||
399 | if (config.stripWhitespaces && result.__text === "" || result.__text.trim() === "") {
|
||
400 | delete result.__text;
|
||
401 | }
|
||
402 | }
|
||
403 | delete result.__cnt;
|
||
404 | |||
405 | if (!config.keepCData && (!result.hasOwnProperty('__text') && result.hasOwnProperty('__cdata'))) {
|
||
406 | return (result.__cdata ? result.__cdata : '');
|
||
407 | }
|
||
408 | |||
409 | if (config.enableToStringFunc && (result.__text || result.__cdata)) {
|
||
410 | result.toString = function toString() {
|
||
411 | return (this.__text ? this.__text : '') + (this.__cdata ? this.__cdata : '');
|
||
412 | };
|
||
413 | }
|
||
414 | |||
415 | return result;
|
||
416 | }
|
||
417 | |||
418 | function deserializeDomChildren(node, parentPath) {
|
||
419 | if (node.nodeType === DOMNodeTypes.DOCUMENT_NODE) {
|
||
420 | return deserializeRootElementChildren(node);
|
||
421 | } else if (node.nodeType === DOMNodeTypes.ELEMENT_NODE) {
|
||
422 | return deserializeElementChildren(node, parentPath);
|
||
423 | } else if (node.nodeType === DOMNodeTypes.TEXT_NODE || node.nodeType === DOMNodeTypes.CDATA_SECTION_NODE) {
|
||
424 | return node.nodeValue;
|
||
425 | } else {
|
||
426 | return null;
|
||
427 | }
|
||
428 | }
|
||
429 | |||
430 | function serializeStartTag(jsObject, elementName, attributeNames, selfClosing) {
|
||
431 | var resultStr = "<" + ((jsObject && jsObject.__prefix) ? (jsObject.__prefix + ":") : "") + elementName;
|
||
432 | |||
433 | if (attributeNames) {
|
||
434 | for (var i = 0; i < attributeNames.length; i++) {
|
||
435 | var attributeName = attributeNames[i];
|
||
436 | var attributeValue = jsObject[attributeName];
|
||
437 | |||
438 | if (config.escapeMode)
|
||
439 | attributeValue = escapeXmlChars(attributeValue);
|
||
440 | |||
441 | resultStr += " " + attributeName.substr(config.attributePrefix.length) + "=";
|
||
442 | |||
443 | if (config.useDoubleQuotes)
|
||
444 | resultStr += '"' + attributeValue + '"';
|
||
445 | else
|
||
446 | resultStr += "'" + attributeValue + "'";
|
||
447 | }
|
||
448 | }
|
||
449 | |||
450 | if (!selfClosing)
|
||
451 | resultStr += ">";
|
||
452 | else
|
||
453 | resultStr += " />";
|
||
454 | |||
455 | return resultStr;
|
||
456 | }
|
||
457 | |||
458 | function serializeEndTag(jsObject, elementName) {
|
||
459 | return "" + ((jsObject && jsObject.__prefix) ? (jsObject.__prefix + ":") : "") + elementName + ">";
|
||
460 | }
|
||
461 | |||
462 | function endsWith(str, suffix) {
|
||
463 | return str.indexOf(suffix, str.length - suffix.length) !== -1;
|
||
464 | }
|
||
465 | |||
466 | function isSpecialProperty(jsonObj, propertyName) {
|
||
467 | if ((config.arrayAccessForm === "property" && endsWith(propertyName.toString(), ("_asArray")))
|
||
468 | || propertyName.toString().indexOf(config.attributePrefix) === 0
|
||
469 | || propertyName.toString().indexOf("__") === 0
|
||
470 | || (jsonObj[propertyName] instanceof Function))
|
||
471 | return true;
|
||
472 | else
|
||
473 | return false;
|
||
474 | }
|
||
475 | |||
476 | function getDataElementCount(jsObject) {
|
||
477 | var count = 0;
|
||
478 | |||
479 | if (jsObject instanceof Object) {
|
||
480 | for (var propertyName in jsObject) {
|
||
481 | if (isSpecialProperty(jsObject, propertyName))
|
||
482 | continue;
|
||
483 | |||
484 | count++;
|
||
485 | }
|
||
486 | }
|
||
487 | |||
488 | return count;
|
||
489 | }
|
||
490 | |||
491 | function getDataAttributeNames(jsObject) {
|
||
492 | var names = [];
|
||
493 | |||
494 | if (jsObject instanceof Object) {
|
||
495 | for (var attributeName in jsObject) {
|
||
496 | if (attributeName.toString().indexOf("__") === -1
|
||
497 | && attributeName.toString().indexOf(config.attributePrefix) === 0) {
|
||
498 | names.push(attributeName);
|
||
499 | }
|
||
500 | }
|
||
501 | }
|
||
502 | |||
503 | return names;
|
||
504 | }
|
||
505 | |||
506 | function serializeComplexTextNodeContents(textNode) {
|
||
507 | var result = "";
|
||
508 | |||
509 | if (textNode.__cdata) {
|
||
510 | result += "<![CDATA[" + textNode.__cdata + "]]>";
|
||
511 | }
|
||
512 | |||
513 | if (textNode.__text) {
|
||
514 | if (config.escapeMode)
|
||
515 | result += escapeXmlChars(textNode.__text);
|
||
516 | else
|
||
517 | result += textNode.__text;
|
||
518 | }
|
||
519 | |||
520 | return result;
|
||
521 | }
|
||
522 | |||
523 | function serializeTextNodeContents(textNode) {
|
||
524 | var result = "";
|
||
525 | |||
526 | if (textNode instanceof Object) {
|
||
527 | result += serializeComplexTextNodeContents(textNode);
|
||
528 | } else if (textNode !== null) {
|
||
529 | if (config.escapeMode)
|
||
530 | result += escapeXmlChars(textNode);
|
||
531 | else
|
||
532 | result += textNode;
|
||
533 | }
|
||
534 | |||
535 | return result;
|
||
536 | }
|
||
537 | |||
538 | function serializeArray(elementArray, elementName, attributes) {
|
||
539 | var result = "";
|
||
540 | |||
541 | if (elementArray.length === 0) {
|
||
542 | result += serializeStartTag(elementArray, elementName, attributes, true);
|
||
543 | } else {
|
||
544 | for (var i = 0; i < elementArray.length; i++) {
|
||
545 | result += serializeJavaScriptObject(elementArray[i], elementName, getDataAttributeNames(elementArray[i]));
|
||
546 | }
|
||
547 | }
|
||
548 | |||
549 | return result;
|
||
550 | }
|
||
551 | |||
552 | function serializeJavaScriptObject(element, elementName, attributes) {
|
||
553 | var result = "";
|
||
554 | |||
555 | if ((element === undefined || element === null || element === '') && config.selfClosingElements) {
|
||
556 | result += serializeStartTag(element, elementName, attributes, true);
|
||
557 | } else if (typeof element === 'object') {
|
||
558 | if (Object.prototype.toString.call(element) === '[object Array]') {
|
||
559 | result += serializeArray(element, elementName, attributes);
|
||
560 | } else if (element instanceof Date) {
|
||
561 | result += serializeStartTag(element, elementName, attributes, false);
|
||
562 | result += element.toISOString();
|
||
563 | result += serializeEndTag(element, elementName);
|
||
564 | } else {
|
||
565 | var childElementCount = getDataElementCount(element);
|
||
566 | if (childElementCount > 0 || element.__text || element.__cdata) {
|
||
567 | result += serializeStartTag(element, elementName, attributes, false);
|
||
568 | result += serializeJavaScriptObjectChildren(element);
|
||
569 | result += serializeEndTag(element, elementName);
|
||
570 | } else if (config.selfClosingElements) {
|
||
571 | result += serializeStartTag(element, elementName, attributes, true);
|
||
572 | } else {
|
||
573 | result += serializeStartTag(element, elementName, attributes, false);
|
||
574 | result += serializeEndTag(element, elementName);
|
||
575 | }
|
||
576 | }
|
||
577 | } else {
|
||
578 | result += serializeStartTag(element, elementName, attributes, false);
|
||
579 | result += serializeTextNodeContents(element);
|
||
580 | result += serializeEndTag(element, elementName);
|
||
581 | }
|
||
582 | |||
583 | return result;
|
||
584 | }
|
||
585 | |||
586 | function serializeJavaScriptObjectChildren(jsObject) {
|
||
587 | var result = "";
|
||
588 | |||
589 | var elementCount = getDataElementCount(jsObject);
|
||
590 | |||
591 | if (elementCount > 0) {
|
||
592 | for (var elementName in jsObject) {
|
||
593 | if (isSpecialProperty(jsObject, elementName))
|
||
594 | continue;
|
||
595 | |||
596 | var element = jsObject[elementName];
|
||
597 | var attributes = getDataAttributeNames(element);
|
||
598 | |||
599 | result += serializeJavaScriptObject(element, elementName, attributes);
|
||
600 | }
|
||
601 | }
|
||
602 | |||
603 | result += serializeTextNodeContents(jsObject);
|
||
604 | |||
605 | return result;
|
||
606 | }
|
||
607 | |||
608 | function parseXml(xml) {
|
||
609 | if (xml === undefined) {
|
||
610 | return null;
|
||
611 | }
|
||
612 | |||
613 | if (typeof xml !== "string") {
|
||
614 | return null;
|
||
615 | }
|
||
616 | |||
617 | var parser = null;
|
||
618 | var domNode = null;
|
||
619 | |||
620 | if (CustomDOMParser) {
|
||
621 | // This branch is used for node.js, with the xmldom parser.
|
||
622 | parser = new CustomDOMParser();
|
||
623 | |||
624 | domNode = parser.parseFromString(xml, "text/xml");
|
||
625 | } else if (window && window.DOMParser) {
|
||
626 | parser = new window.DOMParser();
|
||
627 | var parsererrorNS = null;
|
||
628 | |||
629 | var isIEParser = window.ActiveXObject || "ActiveXObject" in window;
|
||
630 | |||
631 | // IE9+ now is here
|
||
632 | if (!isIEParser) {
|
||
633 | try {
|
||
634 | parsererrorNS = parser.parseFromString("INVALID", "text/xml").childNodes[0].namespaceURI;
|
||
635 | } catch (err) {
|
||
636 | parsererrorNS = null;
|
||
637 | }
|
||
638 | }
|
||
639 | |||
640 | try {
|
||
641 | domNode = parser.parseFromString(xml, "text/xml");
|
||
642 | if (parsererrorNS !== null && domNode.getElementsByTagNameNS(parsererrorNS, "parsererror").length > 0) {
|
||
643 | domNode = null;
|
||
644 | }
|
||
645 | } catch (err) {
|
||
646 | domNode = null;
|
||
647 | }
|
||
648 | } else {
|
||
649 | // IE :(
|
||
650 | if (xml.indexOf("") === 0) {
?")> |
||
651 | ") === 0) {
xml = xml.substr(xml.indexOf("?>") + 2);
?")> |
||
652 | ") === 0) {
}
?")> |
||
653 | |||
654 | ") === 0) {
/* global ActiveXObject */
?")> |
||
655 | ") === 0) {
domNode = new ActiveXObject("Microsoft.XMLDOM");
?")> |
||
656 | ") === 0) {
domNode.async = "false";
?")> |
||
657 | ") === 0) {
domNode.loadXML(xml);
?")> |
||
658 | ") === 0) {
}
?")> |
||
659 | |||
660 | ") === 0) {
return domNode;
?")> |
||
661 | ") === 0) {
}
?")> |
||
662 | |||
663 | ") === 0) {
this.asArray = function asArray(prop) {
?")> |
||
664 | ") === 0) {
if (prop === undefined || prop === null) {
?")> |
||
665 | ") === 0) {
return [];
?")> |
||
666 | ") === 0) {
} else if (prop instanceof Array) {
?")> |
||
667 | ") === 0) {
return prop;
?")> |
||
668 | ") === 0) {
} else {
?")> |
||
669 | ") === 0) {
return [prop];
?")> |
||
670 | ") === 0) {
}
?")> |
||
671 | ") === 0) {
};
?")> |
||
672 | |||
673 | ") === 0) {
this.toXmlDateTime = function toXmlDateTime(dt) {
?")> |
||
674 | ") === 0) {
if (dt instanceof Date) {
?")> |
||
675 | ") === 0) {
return dt.toISOString();
?")> |
||
676 | ") === 0) {
} else if (typeof (dt) === 'number') {
?")> |
||
677 | ") === 0) {
return new Date(dt).toISOString();
?")> |
||
678 | ") === 0) {
} else {
?")> |
||
679 | ") === 0) {
return null;
?")> |
||
680 | ") === 0) {
}
?")> |
||
681 | ") === 0) {
};
?")> |
||
682 | |||
683 | ") === 0) {
this.asDateTime = function asDateTime(prop) {
?")> |
||
684 | ") === 0) {
if (typeof (prop) === "string") {
?")> |
||
685 | ") === 0) {
return xmlDateTimeToDate(prop);
?")> |
||
686 | ") === 0) {
} else {
?")> |
||
687 | ") === 0) {
return prop;
?")> |
||
688 | ") === 0) {
}
?")> |
||
689 | ") === 0) {
};
?")> |
||
690 | |||
691 | ") === 0) {
/*
?")> |
||
692 | ") === 0) {
Internally the logic works in a cycle:
?")> |
||
693 | ") === 0) {
DOM->JS - implemented by custom logic (deserialization).
?")> |
||
694 | ") === 0) {
JS->XML - implemented by custom logic (serialization).
?")> |
||
695 | ") === 0) {
XML->DOM - implemented by browser.
?")> |
||
696 | ") === 0) {
*/
?")> |
||
697 | |||
698 | ") === 0) {
// Transformns an XML string into DOM-tree
?")> |
||
699 | ") === 0) {
this.xml2dom = function xml2dom(xml) {
?")> |
||
700 | ") === 0) {
return parseXml(xml);
?")> |
||
701 | ") === 0) {
};
?")> |
||
702 | |||
703 | ") === 0) {
// Transforms a DOM tree to JavaScript objects.
?")> |
||
704 | ") === 0) {
this.dom2js = function dom2js(domNode) {
?")> |
||
705 | ") === 0) {
return deserializeDomChildren(domNode, null);
?")> |
||
706 | ") === 0) {
};
?")> |
||
707 | |||
708 | ") === 0) {
// Transforms JavaScript objects to a DOM tree.
?")> |
||
709 | ") === 0) {
this.js2dom = function js2dom(jsObject) {
?")> |
||
710 | ") === 0) {
var xml = this.js2xml(jsObject);
?")> |
||
711 | ") === 0) {
return parseXml(xml);
?")> |
||
712 | ") === 0) {
};
?")> |
||
713 | |||
714 | ") === 0) {
// Transformns an XML string into JavaScript objects.
?")> |
||
715 | ") === 0) {
this.xml2js = function xml2js(xml) {
?")> |
||
716 | ") === 0) {
var domNode = parseXml(xml);
?")> |
||
717 | ") === 0) {
if (domNode != null)
?")> |
||
718 | ") === 0) {
return this.dom2js(domNode);
?")> |
||
719 | ") === 0) {
else
?")> |
||
720 | ") === 0) {
return null;
?")> |
||
721 | ") === 0) {
};
?")> |
||
722 | |||
723 | ") === 0) {
// Transforms JavaScript objects into an XML string.
?")> |
||
724 | ") === 0) {
this.js2xml = function js2xml(jsObject) {
?")> |
||
725 | ") === 0) {
return serializeJavaScriptObjectChildren(jsObject);
?")> |
||
726 | ") === 0) {
};
?")> |
||
727 | |||
728 | ") === 0) {
this.getVersion = function getVersion() {
?")> |
||
729 | ") === 0) {
return VERSION;
?")> |
||
730 | ") === 0) {
};
?")> |
||
731 | ") === 0) {
};
?")> |
||
732 | ") === 0) {
});
?")> |