diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
commit | 33058f2b292b3a581333bdfb21b8f671898c5060 (patch) | |
tree | 51c3e392513ec574331b2d3f85c394445ea803c6 /files/zh-cn/archive/jxon/index.html | |
parent | 8b66d724f7caf0157093fb09cfec8fbd0c6ad50a (diff) | |
download | translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.gz translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.bz2 translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.zip |
initial commit
Diffstat (limited to 'files/zh-cn/archive/jxon/index.html')
-rw-r--r-- | files/zh-cn/archive/jxon/index.html | 1513 |
1 files changed, 1513 insertions, 0 deletions
diff --git a/files/zh-cn/archive/jxon/index.html b/files/zh-cn/archive/jxon/index.html new file mode 100644 index 0000000000..1b7c1d69e2 --- /dev/null +++ b/files/zh-cn/archive/jxon/index.html @@ -0,0 +1,1513 @@ +--- +title: JXON +slug: Archive/JXON +translation_of: Archive/JXON +--- +<p><strong>JXON</strong> (无损 JavaScript XML对象注释) 是一个通用名称,通过它定义使用 <a href="/en/XML" title="en/XML">XML</a>的JavaScript对象的表示。 这种转换没有真正的标准,<a href="/zh-CN/docs/Archive/JXON#The_Parker_Convention">但一些公约开始出现在网络上</a>。在某些情况下,必须从JavaScript解释器中读取XML文档的全部内容(例如用于Web应用程序语言或设置XML文档)。在这些情况下,JXON可能是最实用的方法。</p> + +<p>在本文中,我们将演示如何将解析的XML <a href="https://www.w3.org/TR/DOM-Level-2-Core/core.html#i-Document">Document</a>(即<a href="https://www.w3.org/TR/DOM-Level-2-Core/core.html#i-Document">Document</a>的一个实例)转换为JavaScript Object树(即<a href="/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object">Object</a>的嵌套实例树),反之亦然,用一些不同的算法。首先阅读<a href="/zh-CN/docs/XML_介绍">XML介绍文章</a>会比较有帮助。</p> + +<p>如果您想要<strong>一个完整的双向JXON库</strong>(在<a href="/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/JSON">JSON</a>全局对象上建模),请跳至<a href="/zh-CN/docs/Archive/JXON#Appendix.3A_a_complete.2C_bidirectional.2C_JXON_library">专用段落</a>(但请阅读<a href="/zh-CN/docs/Archive/JXON#const_compatibility">关于const语句兼容性的注释</a>)。</p> + +<div class="note"><strong>注意:</strong>如果您只想解决XML文档的某些部分(而不是以JavaScript / JSON为模板目的开始),则使用<a href="/zh-CN/docs/Web/XPath">XPath</a>而不是将整个文档转换为JSON。</div> + +<h2 id="Conversion_snippets">Conversion snippets</h2> + +<p>现在想象你有这个示例XML文档:</p> + +<h5 id="example.xml">example.xml</h5> + +<pre class="brush: xml"><?xml version="1.0"?> +<!DOCTYPE catalog SYSTEM "catalog.dtd"> +<catalog> + <product description="Cardigan Sweater"> + <catalog_item gender="Men's"> + <item_number>QWZ5671</item_number> + <price>39.95</price> + <size description="Medium"> + <color_swatch image="red_cardigan.jpg">Red</color_swatch> + <color_swatch image="burgundy_cardigan.jpg">Burgundy</color_swatch> + </size> + <size description="Large"> + <color_swatch image="red_cardigan.jpg">Red</color_swatch> + <color_swatch image="burgundy_cardigan.jpg">Burgundy</color_swatch> + </size> + </catalog_item> + <catalog_item gender="Women's"> + <item_number>RRX9856</item_number> + <discount_until>Dec 25, 1995</discount_until> + <price>42.50</price> + <size description="Medium"> + <color_swatch image="black_cardigan.jpg">Black</color_swatch> + </size> + </catalog_item> + </product> + <script type="text/javascript"><![CDATA[function matchwo(a,b) { + if (a < b && a < 0) { return 1; } + else { return 0; } +}]]></script> +</catalog> +</pre> + +<p>首先,按照“<a href="/zh-CN/docs/Web/API/Document_Object_Model/How_to_create_a_DOM_tree">如何创建DOM树</a>”文章中的描述,创建一个类似前面示例的DOM树。如果您已经有使用<a href="/zh-CN/docs/Web/API/XMLHttpRequest">XMLHttpRequest</a>的DOM树,请跳到下一段。</p> + +<div class="note"><strong>注意:</strong>如果您正在使用<a href="/zh-CN/docs/Web/API/XMLHttpRequest">XMLHttpRequest</a>实例来检索XML文件,请使用<code>yourRequest.responseXML</code>属性来获取已解析的XML文档。不要使用<code>yourRequest.responseText</code>!</div> + +<p>这里提出的算法(参见:<a href="/zh-CN/docs/Archive/JXON#Algorithm_.231.3A_a_verbose_way">#1</a>,<a href="/zh-CN/docs/Archive/JXON#Algorithm_.232.3A_a_less_verbose_way">#2</a>,<a href="/zh-CN/docs/Archive/JXON#Algorithm_.233.3A_a_synthetic_technique">#3</a>,<a href="/zh-CN/docs/Archive/JXON#Algorithm_.234.3A_a_very_minimalist_way">#4</a>)将只考虑以下类型的节点及其属性:</p> + +<ol> + <li><a href="/zh-CN/docs/Web/API/Document" title="Document 接口提供了一些在浏览器服务中作为页面内容入口点而加载的一些页面,也就是 DOM 树。 DOM 树包括诸如 <body> 和 <table> 之类的元素,及其他元素。其也为文档(document)提供了全局性的函数,例如获取页面的 URL、在文档中创建新的 element 的函数。"><code>Document</code></a> (只作为函数参数),</li> + <li><a href="/zh-CN/docs/Web/API/DocumentFragment" title="DocumentFragment 接口表示一个没有父级文件的最小文档对象。它被当做一个轻量版的 Document 使用,用于存储已排好版的或尚未打理好格式的XML片段。最大的区别是因为DocumentFragment不是真实DOM树的一部分,它的变化不会引起DOM树的重新渲染的操作(reflow) ,且不会导致性能等问题。"><code>DocumentFragment</code></a> (只作为函数参数),</li> + <li><a href="/zh-CN/docs/Web/API/Element" title="Element(元素)接口是 Document的一个对象. 这个接口描述了所有相同种类的元素所普遍具有的方法和属性。 这些继承自Element并且增加了一些额外功能的接口描述了具体的行为. 例如, HTMLElement 接口是所有HTML元素的基础接口, 而 SVGElement 接口是所有SVG元素的基本接口."><code>Element</code></a>,</li> + <li><a href="/zh-CN/docs/Web/API/Text" title="The Text interface represents the textual content of Element or Attr. If an element has no markup within its content, it has a single child implementing Text that contains the element's text. However, if the element contains markup, it is parsed into information items and Text nodes that form its children."><code>Text</code></a> (从不作为函数参数),</li> + <li><a href="/zh-CN/docs/Web/API/CDATASection" title="CDATASection 接口用来表示 CDATA 部分,这一部分可以被使用在XML中, CDATA可以包含那些没有转义字符的文本, 这些没有转义的字符包括但不限于 < 和 & ,他们不需要被转义,但在XML中使用时,保持原样就可以了。"><code>CDATASection</code></a> (从不作为函数参数),</li> + <li><a href="/zh-CN/docs/Web/API/Attr" title="该类型使用对象来表示一个DOM元素的属性。在大多数DOM方法中,你可能会直接通过字符串的方式获取属性值(例如Element.getAttribute()),但是一些函数(例如Element.getAttributeNode())或通过迭代器访问时则返回Attr类型。"><code>Attr</code></a> (从不作为函数参数)。</li> +</ol> + +<p>对于JavaScript的使用来说,这是一个很好的<strong>标准化</strong>的妥协,因为XML文档的所有信息都包含在这些节点类型中。所有其他信息(如处理指令,模式,注释等)都将丢失。这种算法仍然被认为是<strong>无损</strong>的,因为丢失的是<strong>元信息</strong>而不是<strong>信息</strong>。</p> + +<p>为了避免冲突,节点和属性名称的表示<strong>不区分大小写</strong>(总是以<strong>小写</strong>形式呈现),所以使用JavaScript设置的对象的本地属性名称必须总是具有某种大小写(即至少有一个大写字母在他们的名字),如你可以看到下面。</p> + +<p>下面的算法有些基于<a href="/zh-CN/docs/Archive/JXON#The_Parker_Convention">Parker公约(版本0.4)</a>,它规定了<strong><a href="/zh-CN/docs/Web/API/Node/nodeName">标签名称</a>到<a href="/zh-CN/docs/Web/JavaScript/Guide/Working_with_Objects#Objects_and_properties">对象属性名称</a>的转换</strong>以及每个标签(纯文本解析)的所有收集 <a href="/en/DOM/Node.nodeValue" title="en/DOM/Node.nodeValue"><code>text content</code></a>的<strong> <a href="/en/JavaScript/Reference/Operators/typeof" title="en/JavaScript/Reference/Operators/typeof"><code>typeof</code></a></strong> <strong>的识别</strong>。但<a href="/zh-CN/docs/Archive/JXON#Code_considerations">有一些分歧</a>(所以,可以说我们遵循我们的惯例)。而且,对于设想的节点,<strong>所有算法都是同样无损的</strong>。</p> + +<p>我们认为<a href="/zh-CN/docs/Archive/JXON#Algorithm_.233.3A_a_synthetic_technique">第三种算法</a>是<strong>最具代表性和实用性的JXON解析算法</strong>。</p> + +<p>现在让我们将<code>doc</code>(DOM树)序列化为一个JavaScript对象树(您可以阅读关于<a href="/zh-CN/docs/Web/JavaScript/Guide/Working_with_Objects">使用对象</a>以及<a href="/zh-CN/docs/Learn/JavaScript/Objects">Javascript如何面向对象</a>的更多信息)。我们可以使用几种算法将其内容转换为Javascript对象树。</p> + +<h3 id="算法_1_一个冗长的方式">算法 #1: 一个冗长的方式</h3> + +<p>这个简单的递归构造函数将一个XML DOM树转换成一个JavaScript对象树。每个元素的文本内容都存储在<code>keyValue</code>属性中,而<code>nodeAttributes</code>(如果存在)列在子对象<code>keyAttributes</code>下。构造函数的参数可以是整个XML <code>Document</code>,<code>DocumentFragment</code>或简单的<code>Element</code>节点。</p> + +<pre class="brush: js">/*\ +|*| +|*| JXON Snippet #1 - Mozilla Developer Network +|*| +|*| https://developer.mozilla.org/en-US/docs/JXON +|*| https://developer.mozilla.org/User:fusionchess +|*| +|*| This framework is released under the GNU Public License, version 3 or later. +|*| http://www.gnu.org/licenses/gpl-3.0-standalone.html +|*| +\*/ + +function parseText (sValue) { + if (/^\s*$/.test(sValue)) { return null; } + if (/^(?:true|false)$/i.test(sValue)) { return sValue.toLowerCase() === "true"; } + if (isFinite(sValue)) { return parseFloat(sValue); } + if (isFinite(Date.parse(sValue))) { return new Date(sValue); } + return sValue; +} + +function JXONTree (oXMLParent) { + var nAttrLen = 0, nLength = 0, sCollectedTxt = ""; + if (oXMLParent.hasChildNodes()) { + for (var oNode, sProp, vContent, nItem = 0; nItem < oXMLParent.childNodes.length; nItem++) { + oNode = oXMLParent.childNodes.item(nItem); + if ((oNode.nodeType - 1 | 1) === 3) { sCollectedTxt += oNode.nodeType === 3 ? oNode.nodeValue.trim() : oNode.nodeValue; } // nodeType is "Text" (3) or "CDATASection" (4) + else if (oNode.nodeType === 1 && !oNode.prefix) { // nodeType is "Element" (1) + sProp = oNode.nodeName.toLowerCase(); + vContent = new JXONTree(oNode); + if (this.hasOwnProperty(sProp)) { + if (this[sProp].constructor !== Array) { this[sProp] = [this[sProp]]; } + this[sProp].push(vContent); + } else { this[sProp] = vContent; nLength++; } + } + } + this.keyValue = parseText(sCollectedTxt); + } else { this.keyValue = null; } + if (oParentNode.hasAttributes && oXMLParent.hasAttributes()) { + var oAttrib; + this.keyAttributes = {}; + for (nAttrLen; nAttrLen < oXMLParent.attributes.length; nAttrLen++) { + oAttrib = oXMLParent.attributes.item(nAttrLen); + this.keyAttributes[oAttrib.name.toLowerCase()] = parseText(oAttrib.value.trim()); + } + } + /* + * Optional properties... + + this.keyLength = nLength; + this.attributesLength = nAttrLen; + // this.DOMNode = oXMLParent; + + */ + + /* Object.freeze(this); */ +} + +/* +* Optional methods... Uncomment the optional properties first! + +JXONTree.prototype.valueOf = function () { return this.keyValue; }; +JXONTree.prototype.toString = function () { return String(this.keyValue); }; +JXONTree.prototype.getItem = function (nItem) { + if (nLength === 0) { return null; } + var nCount = 0; + for (var sKey in this) { if (nCount === nItem) { return this[sKey]; } nCount++; } + return null; +}; +JXONTree.prototype.getAttribute = function (nAttrId) { + if (nAttrLen === 0 || nAttrId + 1 > nAttrLen) { return null; } + var nAttr = 0; + for (var sAttrName in this.keyAttributes) { if (nAttr === nAttrId) { return this.keyAttributes[sAttrName]; } nAttr++; } + return null; +}; +JXONTree.prototype.hasChildren = function () { return this.keyLength > 0; }; + +*/ + +var myObject = new JXONTree(doc); +// we got our javascript object! try: alert(JSON.stringify(myObject)); +</pre> + +<div class="note"><strong>注意:</strong>如果你想冻结整个对象树(因为XML文档的“静态”性质),取消注释字符串:<code>/* Object.freeze(this); */</code>。 <code><a href="/en/JavaScript/Reference/Global_Objects/Object/freeze" title="en/JavaScript/Reference/Global_Objects/Object/freeze">Object.freeze()</a></code>方法防止将新属性添加到该属性中,防止现有属性被删除,并防止现有属性或其可枚举性,可配置性或可写性发生更改。本质上,对象树是有效的不可变的。</div> + +<p> </p> + +<p>用这个算法我们的<a href="/zh-CN/docs/Archive/JXON#example.xml">例子</a>变成:</p> + +<pre class="brush: js">{ + "catalog": { + "product": { + "catalog_item": [{ + "item_number": { + "keyValue": "QWZ5671" + }, + "price": { + "keyValue": 39.95 + }, + "size": [{ + "color_swatch": [{ + "keyValue": "Red", + "keyAttributes": { + "image": "red_cardigan.jpg" + } + }, { + "keyValue": "Burgundy", + "keyAttributes": { + "image": "burgundy_cardigan.jpg" + } + }], + "keyValue": null, + "keyAttributes": { + "description": "Medium" + } + }, { + "color_swatch": [{ + "keyValue": "Red", + "keyAttributes": { + "image": "red_cardigan.jpg" + } + }, { + "keyValue": "Burgundy", + "keyAttributes": { + "image": "burgundy_cardigan.jpg" + } + }], + "purchased": { + "keyValue": null + }, + "keyValue": null, + "keyAttributes": { + "description": "Large" + } + }], + "keyValue": null, + "keyAttributes": { + "gender": "Men's" + } + }, { + "item_number": { + "keyValue": "RRX9856" + }, + "discount_until": { + "keyValue": new Date(1995, 11, 25) + }, + "price": { + "keyValue": 42.5 + }, + "size": { + "color_swatch": { + "keyValue": "Black", + "keyAttributes": { + "image": "black_cardigan.jpg" + } + }, + "keyValue": null, + "keyAttributes": { + "description": "Medium" + } + }, + "keyValue": null, + "keyAttributes": { + "gender": "Women's" + } + }], + "keyValue": null, + "keyAttributes": { + "description": "Cardigan Sweater" + } + }, + "script": { + "keyValue": "function matchwo(a,b) {\n if (a < b && a < 0) { return 1; }\n else { return 0; }\n}", + "keyAttributes": { + "type": "text/javascript" + } + }, + "keyValue": null + }, + "keyValue": null +} +</pre> + +<p>如果您部分了解XML文档的结构,则可以使用这种技术。</p> + +<h3 id="算法_2_一个不太冗长的方式">算法 #2: 一个不太冗长的方式</h3> + +<p>这里是另一个更简单的转换方法,其中<code>nodeAttributes</code>列在子节点的同一对象下,但带有“@”前缀(由<a href="http://badgerfish.ning.com/">BadgerFish Convention</a>提出)。如上所述,文本内容存储在<code>keyValue</code>属性中。构造函数的参数可以是整个XML <code>Document</code>,一个<code>DocumentFragment</code>或简单的<code>Element</code>节点。</p> + +<pre class="brush: js">/*\ +|*| +|*| JXON Snippet #2 - Mozilla Developer Network +|*| +|*| https://developer.mozilla.org/en-US/docs/JXON +|*| https://developer.mozilla.org/User:fusionchess +|*| +|*| This framework is released under the GNU Public License, version 3 or later. +|*| http://www.gnu.org/licenses/gpl-3.0-standalone.html +|*| +\*/ + +function parseText (sValue) { + if (/^\s*$/.test(sValue)) { return null; } + if (/^(?:true|false)$/i.test(sValue)) { return sValue.toLowerCase() === "true"; } + if (isFinite(sValue)) { return parseFloat(sValue); } + if (isFinite(Date.parse(sValue))) { return new Date(sValue); } + return sValue; +} + +function JXONTree (oXMLParent) { + if (oXMLParent.hasChildNodes()) { + var sCollectedTxt = ""; + for (var oNode, sProp, vContent, nItem = 0; nItem < oXMLParent.childNodes.length; nItem++) { + oNode = oXMLParent.childNodes.item(nItem); + if ((oNode.nodeType - 1 | 1) === 3) { sCollectedTxt += oNode.nodeType === 3 ? oNode.nodeValue.trim() : oNode.nodeValue; } + else if (oNode.nodeType === 1 && !oNode.prefix) { + sProp = oNode.nodeName.toLowerCase(); + vContent = new JXONTree(oNode); + if (this.hasOwnProperty(sProp)) { + if (this[sProp].constructor !== Array) { this[sProp] = [this[sProp]]; } + this[sProp].push(vContent); + } else { this[sProp] = vContent; } + } + } + if (sCollectedTxt) { this.keyValue = parseText(sCollectedTxt); } + } + if (oParentNode.hasAttributes && oXMLParent.hasAttributes()) { + var oAttrib; + for (var nAttrib = 0; nAttrib < oXMLParent.attributes.length; nAttrib++) { + oAttrib = oXMLParent.attributes.item(nAttrib); + this["@" + oAttrib.name.toLowerCase()] = parseText(oAttrib.value.trim()); + } + } + /* Object.freeze(this); */ +} + +var myObject = new JXONTree(doc); +// we got our javascript object! try: alert(JSON.stringify(myObject)); +</pre> + +<div class="note"><strong>注意:</strong>如果你想冻结整个对象树(因为XML文档的“静态”性质),取消注释字符串:<code>/* Object.freeze(this); */</code>。 <code><a href="/en/JavaScript/Reference/Global_Objects/Object/freeze" title="en/JavaScript/Reference/Global_Objects/Object/freeze">Object.freeze()</a></code>方法防止将新属性添加到该属性中,防止现有属性被删除,并防止现有属性或其可枚举性,可配置性或可写性发生更改。本质上,对象树是有效的不可变的。</div> + +<p>用这个算法我们的<a href="/zh-CN/docs/Archive/JXON#example.xml">例子</a>变成:</p> + +<pre class="brush: js">{ + "catalog": { + "product": { + "catalog_item": [{ + "item_number": { + "keyValue": "QWZ5671" + }, + "price": { + "keyValue": 39.95 + }, + "size": [{ + "color_swatch": [{ + "keyValue": "Red", + "@image": "red_cardigan.jpg" + }, { + "keyValue": "Burgundy", + "@image": "burgundy_cardigan.jpg" + }], + "@description": "Medium" + }, { + "color_swatch": [{ + "keyValue": "Red", + "@image": "red_cardigan.jpg" + }, { + "keyValue": "Burgundy", + "@image": "burgundy_cardigan.jpg" + }], + "@description": "Large" + }], + "@gender": "Men's" + }, { + "item_number": { + "keyValue": "RRX9856" + }, + "discount_until": { + "keyValue": new Date(1995, 11, 25) + }, + "price": { + "keyValue": 42.5 + }, + "size": { + "color_swatch": { + "keyValue": "Black", + "@image": "black_cardigan.jpg" + }, + "@description": "Medium" + }, + "@gender": "Women's" + }], + "@description": "Cardigan Sweater" + }, + "script": { + "keyValue": "function matchwo(a,b) {\n if (a < b && a < 0) { return 1; }\n else { return 0; }\n}", + "@type": "text/javascript" + } + } +} +</pre> + +<p>如果您部分了解XML文档的结构,则可以使用这种技术。</p> + +<h3 id="Algorithm_3_一种组合的技巧">Algorithm #3: 一种组合的技巧</h3> + +<p>这是另一种转换方法。这个算法是最接近<a href="/zh-CN/docs/Archive/JXON#The_Parker_Convention">Parker约定</a>的。除了不包含除<code>Text</code>或<code>CDATASection</code>以外的其他可识别节点的节点不被视为对象,而是直接作为布尔值,字符串,数字或<code>Date</code>对象(请参阅<a href="/zh-CN/docs/Archive/JXON#The_Parker_Convention">Parker约定</a>)。空节点(即不包含其他<code>Element</code>节点,<code>Text</code>节点,<code>CDATASection</code>节点或<code>Attr</code>节点)的默认值为<code>true</code>(请参阅<a href="/zh-CN/docs/Archive/JXON#Code_considerations">代码注意事项</a>)。另外,这次我们使用一个函数来代替构造函数。函数的参数可以是整个XML <a href="/zh-CN/docs/Web/API/Document" title="Document 接口提供了一些在浏览器服务中作为页面内容入口点而加载的一些页面,也就是 DOM 树。 DOM 树包括诸如 <body> 和 <table> 之类的元素,及其他元素。其也为文档(document)提供了全局性的函数,例如获取页面的 URL、在文档中创建新的 element 的函数。"><code>Document</code></a>,一个<a href="/zh-CN/docs/Web/API/DocumentFragment" title="DocumentFragment 接口表示一个没有父级文件的最小文档对象。它被当做一个轻量版的 Document 使用,用于存储已排好版的或尚未打理好格式的XML片段。最大的区别是因为DocumentFragment不是真实DOM树的一部分,它的变化不会引起DOM树的重新渲染的操作(reflow) ,且不会导致性能等问题。"><code>DocumentFragment</code></a>,或者只是一个 <a href="/zh-CN/docs/Web/API/Element" title="Element(元素)接口是 Document的一个对象. 这个接口描述了所有相同种类的元素所普遍具有的方法和属性。 这些继承自Element并且增加了一些额外功能的接口描述了具体的行为. 例如, HTMLElement 接口是所有HTML元素的基础接口, 而 SVGElement 接口是所有SVG元素的基本接口."><code>Element</code></a> 节点。根据<a href="http://badgerfish.ning.com/">BadgerFish公约</a>的建议,<code>nodeAttributes</code>具有“@”前缀。<strong>在很多情况下,这是最实用的转换方法。</strong></p> + +<pre class="brush: js">/*\ +|*| +|*| JXON Snippet #3 - Mozilla Developer Network +|*| +|*| https://developer.mozilla.org/en-US/docs/JXON +|*| https://developer.mozilla.org/User:fusionchess +|*| +|*| This framework is released under the GNU Public License, version 3 or later. +|*| http://www.gnu.org/licenses/gpl-3.0-standalone.html +|*| +\*/ + +function parseText (sValue) { + if (/^\s*$/.test(sValue)) { return null; } + if (/^(?:true|false)$/i.test(sValue)) { return sValue.toLowerCase() === "true"; } + if (isFinite(sValue)) { return parseFloat(sValue); } + if (isFinite(Date.parse(sValue))) { return new Date(sValue); } + return sValue; +} + +function getJXONTree (oXMLParent) { + var vResult = /* put here the default value for empty nodes! */ true, nLength = 0, sCollectedTxt = ""; + if (oXMLParent.hasAttributes && oXMLParent.hasAttributes()) { + vResult = {}; + for (nLength; nLength < oXMLParent.attributes.length; nLength++) { + oAttrib = oXMLParent.attributes.item(nLength); + vResult["@" + oAttrib.name.toLowerCase()] = parseText(oAttrib.value.trim()); + } + } + if (oXMLParent.hasChildNodes()) { + for (var oNode, sProp, vContent, nItem = 0; nItem < oXMLParent.childNodes.length; nItem++) { + oNode = oXMLParent.childNodes.item(nItem); + if (oNode.nodeType === 4) { sCollectedTxt += oNode.nodeValue; } /* nodeType is "CDATASection" (4) */ + else if (oNode.nodeType === 3) { sCollectedTxt += oNode.nodeValue.trim(); } /* nodeType is "Text" (3) */ + else if (oNode.nodeType === 1 && !oNode.prefix) { /* nodeType is "Element" (1) */ + if (nLength === 0) { vResult = {}; } + sProp = oNode.nodeName.toLowerCase(); + vContent = getJXONTree(oNode); + if (vResult.hasOwnProperty(sProp)) { + if (vResult[sProp].constructor !== Array) { vResult[sProp] = [vResult[sProp]]; } + vResult[sProp].push(vContent); + } else { vResult[sProp] = vContent; nLength++; } + } + } + } + if (sCollectedTxt) { nLength > 0 ? vResult.keyValue = parseText(sCollectedTxt) : vResult = parseText(sCollectedTxt); } + /* if (nLength > 0) { Object.freeze(vResult); } */ + return vResult; +} + +var myObject = getJXONTree(doc); +// we got our javascript object! try: alert(JSON.stringify(myObject)); +</pre> + +<div class="note"><strong>注意:</strong>如果你想冻结整个对象树(因为XML文档的“静态”性质),取消注释字符串:<code>/* Object.freeze(this); */</code>。 <code><a href="/en/JavaScript/Reference/Global_Objects/Object/freeze" title="en/JavaScript/Reference/Global_Objects/Object/freeze">Object.freeze()</a></code>方法防止将新属性添加到该属性中,防止现有属性被删除,并防止现有属性或其可枚举性,可配置性或可写性发生更改。本质上,对象树是有效的不可变的。</div> + +<p>用这个算法我们的<a href="/zh-CN/docs/Archive/JXON#example.xml">例子</a>变成:</p> + +<pre class="brush: js">{ + "catalog": { + "product": { + "@description": "Cardigan Sweater", + "catalog_item": [{ + "@gender": "Men's", + "item_number": "QWZ5671", + "price": 39.95, + "size": [{ + "@description": "Medium", + "color_swatch": [{ + "@image": "red_cardigan.jpg", + "keyValue": "Red" + }, { + "@image": "burgundy_cardigan.jpg", + "keyValue": "Burgundy" + }] + }, { + "@description": "Large", + "color_swatch": [{ + "@image": "red_cardigan.jpg", + "keyValue": "Red" + }, { + "@image": "burgundy_cardigan.jpg", + "keyValue": "Burgundy" + }] + }] + }, { + "@gender": "Women's", + "item_number": "RRX9856", + "discount_until": new Date(1995, 11, 25), + "price": 42.5, + "size": { + "@description": "Medium", + "color_swatch": { + "@image": "black_cardigan.jpg", + "keyValue": "Black" + } + } + }] + }, + "script": { + "@type": "text/javascript", + "keyValue": "function matchwo(a,b) {\n if (a < b && a < 0) { return 1; }\n else { return 0; }\n}" + } + } +} +</pre> + +<p>如果您知道XML文档的结构,这是推荐的技术。</p> + +<h3 id="算法_4_一个非常简约的方式">算法 #4: 一个非常简约的方式</h3> + +<p>以下是另一种可以实现的转换方法。它也非常接近<a href="/zh-CN/docs/Archive/JXON#The_Parker_Convention">Parker约定</a>。使用此算法,包含同一级别中的其他子元素,文本或<code>CDATASection</code>节点的所有元素节点都将被视为<code>Boolean</code> ,<code>Number</code>, <code>String</code>,或<code>Date</code>构造函数的实例。因此,任何子元素节点(如果存在)将嵌套在这些类型的对象中。</p> + +<p>For example:</p> + +<pre class="brush: xml"><employee type="usher">John Smith</employee> +<manager>Lisa Carlucci</manager> +</pre> + +<p>becomes</p> + +<pre class="brush: js">var myObject = { + "employee": new String("John Smith"), + "manager": "Lisa Carlucci" +}; + +myObject.employee["@type"] = "usher"; + +// test + +alert(myObject.manager); // "Lisa Carlucci" +alert(myObject.employee["@type"]); // "usher" +alert(myObject.employee); // "John Smith" +</pre> + +<div class="note"><strong>注意:</strong>这个算法代表了转换的特殊情况。<strong>生成的JavaScript对象树不可<a href="/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify">字符串化</a></strong>(请参阅<a href="#Code_considerations" title="Code considerations">Code considerations</a>)。内部JavaScript访问非常实用,但如果要通过JSON字符串传输树,请不要使用它!</div> + +<p>对于第三种算法,不包含除Text或<code>CDATASection</code>之外的其他可识别节点的节点不被视为对象,而是直接作为<code>Boolean</code> ,<code>Number</code>(原始值), <code>String</code>,或<code>Date</code>对象;而空节点(即,不包含其他<code>Element</code>节点,<code>Text</code>节点,<code>CDATASection</code>节点或<code>Attr</code>节点)具有默认值<code>true</code>。至于第三个算法,它不是使用构造函数,而是一个函数。该函数的参数可以是整个XML文档,一个<code>DocumentFragment</code>或简单的<code>Element</code>节点。根据BadgerFish公约的建议,<code>nodeAttributes</code>具有“@”前缀。</p> + +<pre class="brush: js">/*\ +|*| +|*| JXON Snippet #4 - Mozilla Developer Network +|*| +|*| https://developer.mozilla.org/en-US/docs/JXON +|*| https://developer.mozilla.org/User:fusionchess +|*| +|*| This framework is released under the GNU Public License, version 3 or later. +|*| http://www.gnu.org/licenses/gpl-3.0-standalone.html +|*| +\*/ + +function parseText (sValue) { + if (/^\s*$/.test(sValue)) { return null; } + if (/^(?:true|false)$/i.test(sValue)) { return sValue.toLowerCase() === "true"; } + if (isFinite(sValue)) { return parseFloat(sValue); } + if (isFinite(Date.parse(sValue))) { return new Date(sValue); } + return sValue; +} + +function objectify (vValue) { + if (vValue === null) { + return new (function() { + this.toString = function() { return "null"; } + this.valueOf = function() { return null; } + })(); + } + return vValue instanceof Object ? vValue : new vValue.constructor(vValue); +} + +var aTmpEls = []; // loaded element nodes cache + +function getJXONTree (oXMLParent) { + var sProp, vContent, vResult, nLength = 0, nLevelStart = aTmpEls.length, + nChildren = oXMLParent.hasChildNodes() ? oXMLParent.childNodes.length : 0, sCollectedTxt = ""; + + for (var oNode, nItem = 0; nItem < nChildren; nItem++) { + oNode = oXMLParent.childNodes.item(nItem); + if (oNode.nodeType === 4) { sCollectedTxt += oNode.nodeValue; } /* nodeType is "CDATASection" (4) */ + else if (oNode.nodeType === 3) { sCollectedTxt += oNode.nodeValue.trim(); } /* nodeType is "Text" (3) */ + else if (oNode.nodeType === 1 && !oNode.prefix) { aTmpEls.push(oNode); } /* nodeType is "Element" (1) */ + } + + var nLevelEnd = aTmpEls.length, vBuiltVal = parseText(sCollectedTxt); + + if (oParentNode.hasAttributes && oXMLParent.hasAttributes()) { + vResult = objectify(vBuiltVal); + for (nLength; nLength < oXMLParent.attributes.length; nLength++) { + oAttrib = oXMLParent.attributes.item(nLength); + vResult["@" + oAttrib.name.toLowerCase()] = parseText(oAttrib.value.trim()); + } + } else if (nLevelEnd > nLevelStart) { vResult = objectify(vBuiltVal); } + + for (var nElId = nLevelStart; nElId < nLevelEnd; nElId++) { + sProp = aTmpEls[nElId].nodeName.toLowerCase(); + vContent = getJXONTree(aTmpEls[nElId]); + if (vResult.hasOwnProperty(sProp)) { + if (vResult[sProp].constructor !== Array) { vResult[sProp] = [vResult[sProp]]; } + vResult[sProp].push(vContent); + } else { vResult[sProp] = vContent; nLength++; } + } + + aTmpEls.length = nLevelStart; + + if (nLength === 0) { vResult = sCollectedTxt ? vBuiltVal : /* put here the default value for empty nodes: */ true; } + /* else { Object.freeze(vResult); } */ + + return vResult; +} + +var myObject = getJXONTree(doc); +alert(myObject.catalog.product.catalog_item[1].size.color_swatch["@image"]); // "black_cardigan.jpg" +alert(myObject.catalog.product.catalog_item[1].size.color_swatch); // "Black" ! +</pre> + +<p> </p> + +<div class="note"><strong>注意:</strong>如果你想冻结整个对象树(因为XML文档的“静态”性质),取消注释字符串:<code>/* Object.freeze(this); */</code>。 <code><a href="/en/JavaScript/Reference/Global_Objects/Object/freeze" title="en/JavaScript/Reference/Global_Objects/Object/freeze">Object.freeze()</a></code>方法防止将新属性添加到该属性中,防止现有属性被删除,并防止现有属性或其可枚举性,可配置性或可写性发生更改。本质上,对象树是有效的不可变的。</div> + +<p>如果您知道XML文档的结构,这是一种可能的技术。</p> + +<p> </p> + +<h3 id="反向算法">反向算法</h3> + +<p>为了从JavaScript对象树开始构建一个新的XML文档,可以将这里提出的算法颠倒过来。为了简单,我们将在这里提出一个例子,在一个单一的方法,代表了所有我们的算法的反演。</p> + +<pre class="brush: js">/*\ +|*| +|*| JXON Snippet #5 - Mozilla Developer Network +|*| +|*| https://developer.mozilla.org/en-US/docs/JXON +|*| https://developer.mozilla.org/User:fusionchess +|*| +|*| This framework is released under the GNU Public License, version 3 or later. +|*| http://www.gnu.org/licenses/gpl-3.0-standalone.html +|*| +\*/ + +function createXML (oObjTree) { + function loadObjTree (oParentEl, oParentObj) { + var vValue, oChild; + if (oParentObj.constructor === String || oParentObj.constructor === Number || oParentObj.constructor === Boolean) { + oParentEl.appendChild(oNewDoc.createTextNode(oParentObj.toString())); /* verbosity level is 0 or 1 */ + if (oParentObj === oParentObj.valueOf()) { return; } + } else if (oParentObj.constructor === Date) { + oParentEl.appendChild(oNewDoc.createTextNode(oParentObj.toGMTString())); + } + for (var sName in oParentObj) { + if (isFinite(sName)) { continue; } /* verbosity level is 0 */ + vValue = oParentObj[sName]; + if (sName === "keyValue") { + if (vValue !== null && vValue !== true) { oParentEl.appendChild(oNewDoc.createTextNode(vValue.constructor === Date ? vValue.toGMTString() : String(vValue))); } + } else if (sName === "keyAttributes") { /* verbosity level is 3 */ + for (var sAttrib in vValue) { oParentEl.setAttribute(sAttrib, vValue[sAttrib]); } + } else if (sName.charAt(0) === "@") { + oParentEl.setAttribute(sName.slice(1), vValue); + } else if (vValue.constructor === Array) { + for (var nItem = 0; nItem < vValue.length; nItem++) { + oChild = oNewDoc.createElement(sName); + loadObjTree(oChild, vValue[nItem]); + oParentEl.appendChild(oChild); + } + } else { + oChild = oNewDoc.createElement(sName); + if (vValue instanceof Object) { + loadObjTree(oChild, vValue); + } else if (vValue !== null && vValue !== true) { + oChild.appendChild(oNewDoc.createTextNode(vValue.toString())); + } + oParentEl.appendChild(oChild); + } + } + } + const oNewDoc = document.implementation.createDocument("", "", null); + loadObjTree(oNewDoc, oObjTree); + return oNewDoc; +} + +var newDoc = createXML(myObject); +// we got our Document instance! try: alert((new XMLSerializer()).serializeToString(newDoc)); +</pre> + +<div class="note"><strong>注意:</strong>通过这个代码,<code>Date</code>实例(如果存在的话)通过<a href="/en/JavaScript/Reference/Global_Objects/Date/toGMTString" title="toGMTString"><code>toGMTString()</code></a> 方法转换为 <a href="/en/JavaScript/Reference/Global_Objects/String" title="String">Strings</a> 。没有什么禁止使用任何其他转换方法。此外,具有<code>true</code>值的树的所有属性都将被转换为没有文本节点的空元素(请参阅 <a href="#Code_considerations" title="Code considerations">Code considerations</a>)。</div> + +<p>如果要自动创建XML文档,这是一个很好的解决方案。但是,如果要重新构建以前转换为JSON的XML文档,这是一个不错的选择。虽然<strong>双向转换是非常忠实的</strong>(除了<a href="/zh-CN/docs/Web/API/CDATASection" title="CDATASection 接口用来表示 CDATA 部分,这一部分可以被使用在XML中, CDATA可以包含那些没有转义字符的文本, 这些没有转义的字符包括但不限于 < 和 & ,他们不需要被转义,但在XML中使用时,保持原样就可以了。"><code>CDATASection</code></a>节点,它们将被转换成文本节点),但这个过程是不必要的成本。事实上,如果您的目标是编辑XML文档,强烈建议您使用它而不是创建一个新的。</p> + +<h2 id="The_Parker_Convention">The Parker Convention</h2> + +<p>上面列出的用于将XML文档转换为<a href="/en/JSON" title="en/JSON">JSON</a>(通常称为“JXON算法”)的功能或多或少地基于Parker公约(尤其是关于将标签名称转换为对象属性名称,识别所有收集到的每个标签的文本内容以及单独的<code>Text</code>和/或<code>CDATASection</code>节点吸收为原始值)。It is called “Parker Convention” in opposition to “BadgerFish Convention”, after the comic Parker & Badger by Cuadrado. See also: <a href="http://badgerfish.ning.com/" title="BadgerFish convention">BadgerFish Convention</a>.</p> + +<p>以下是来自 <a href="http://code.google.com/p/xml2json-xslt/" title="xml2json-xslt project">xml2json-xslt</a>项目网站的“<a href="http://code.google.com/p/xml2json-xslt/wiki/TransformingRules" title="TransformingRules – xml2json-xslt">TransformingRules</a>”页面的Parker Convention文章(版本0.4)的转录。</p> + +<p>本公约是为了规范从<a href="/en/XSLT" title="en/XSLT">XSLT</a>到 <a href="/en/JSON" title="en/JSON">JSON</a> 的转换而编写的,所以它的一部分对于JavaScript来说是徒劳的。</p> + +<div class="note"><strong>注意:</strong>2013年10月29日,万维网联盟(World Wide Web Consortium)在一篇关于将<a href="/zh-CN/docs/Web/HTML/Global_attributes#itemid">HTML5微数据</a>转换为<em><a href="/en/JSON" title="en/JSON">JSON</a></em>的官方算法的备注中转载。但是,HTML微数据不是HTML:微数据是HTML的格式化子集。</div> + +<h3 id="Translation_JSON">Translation JSON</h3> + +<ol> + <li> + <p>The root element will be absorbed, for there is only one:</p> + + <pre class="brush: xml"><root>test</root></pre> + + <p>becomes</p> + + <pre class="brush: js">"test" +</pre> + </li> + <li> + <p>Element names become object properties:</p> + + <pre class="brush: xml"><root><name>Xml</name><encoding>ASCII</encoding></root></pre> + + <p>becomes</p> + + <pre class="brush: js">{ + "name": "Xml", + "encoding": "ASCII" +} +</pre> + </li> + <li> + <p>Numbers are recognized (integers and decimals):</p> + + <pre class="brush: xml"><root><age>12</age><height>1.73</height></root></pre> + + <p>becomes</p> + + <pre class="brush: js">{ + "age": 12, + "height": 1.73 +} +</pre> + </li> + <li> + <p>Booleans are recognized case insensitive:</p> + + <pre class="brush: xml"><root><checked>True</checked><answer>FALSE</answer></root></pre> + + <p>becomes</p> + + <pre class="brush: js">{ + "checked": true, + "answer": false +} +</pre> + </li> + <li> + <p>Strings are escaped:</p> + + <pre class="brush: xml"><root>Quote: &quot; New-line: +</root> +</pre> + + <p>becomes</p> + + <pre class="brush: js">"Quote: \" New-line:\n"</pre> + </li> + <li> + <p>Empty elements will become null:</p> + + <pre class="brush: xml"><root><nil/><empty></empty></root></pre> + + <p>becomes</p> + + <pre class="brush: js">{ + "nil": null, + "empty": null +} +</pre> + </li> + <li> + <p>If all sibling elements have the same name, they become an array</p> + + <pre class="brush: xml"><root><item>1</item><item>2</item><item>three</item></root> +</pre> + + <p>becomes</p> + + <pre class="brush: js">[1, 2, "three"] +</pre> + </li> + <li> + <p>Mixed mode text-nodes, comments and attributes get absorbed:</p> + + <pre class="brush: xml"><root version="1.0">testing<!--comment--><element test="true">1</element></root> +</pre> + + <p>becomes</p> + + <pre class="brush: js">{ "element": true } +</pre> + </li> + <li> + <p>Namespaces get absorbed, and prefixes will just be part of the property name:</p> + + <pre class="brush: xml"><root xmlns:ding="http://zanstra.com/ding"><ding:dong>binnen</ding:dong></root> +</pre> + + <p>becomes</p> + + <pre class="brush: js">{ "ding:dong" : "binnen" } +</pre> + </li> +</ol> + +<div class="note"><strong>注意:</strong>我们的算法符合第2,3,4和7点。第三和第四个算法也符合第6点(但是<code>true</code>而不是<code>null</code> - 请参阅<a href="#Code_considerations" title="Code considerations">Code considerations</a>)。第5点由JavaScript方法<code><a href="/en/JavaScript/Reference/Global_Objects/JSON/stringify" title="en/JavaScript/Reference/Global_Objects/JSON/stringify">JSON.stringify()</a></code>自动管理。关于第9点,我们选择忽略所有有前缀的节点;你可以通过从我们的算法中删除字符串<code>&& !oNode.prefix</code>来包含它们(参见 <a href="#Code_considerations" title="Code considerations">Code considerations</a>))。</div> + +<h3 id="额外的JavaScript转换">额外的JavaScript转换</h3> + +<p>This is the same as the JSON translation, but with these extras:</p> + +<ol> + <li> + <p>Property names are only escaped when necessary</p> + + <pre class="brush: xml"><root><while>true</while><wend>false</wend><only-if/></root> +</pre> + + <p>becomes</p> + + <pre class="brush: js">{ + "while": true, + wend: false, + "only-if": null +} +</pre> + </li> + <li> + <p>Within a string, closing elements "</" are escaped as "<\/"</p> + + <pre class="brush: xml"><root><![CDATA[<script>alert("YES");</script>]]></root></pre> + + <p>becomes</p> + + <pre class="brush: js">{ script: "<script>alert(\"YES\")<\/script>" } +</pre> + </li> + <li> + <p>Dates are created as new <a href="/en/JavaScript/Reference/Global_Objects/Date" title="Date"><code>Date</code></a> objects</p> + + <pre class="brush: xml"><root>2006-12-25</root></pre> + + <p>becomes</p> + + <pre class="brush: js">new Date(2006, 12 - 1, 25) +</pre> + </li> + <li> + <p>Attributes and comments are shown as comments (for testing purposes):</p> + + <pre class="brush: xml"><!--testing--><root><test version="1.0">123</test></root> +</pre> + + <p>becomes</p> + + <pre class="brush: js">/* testing */ { test /* @version = "1.0" */ : 123} +</pre> + </li> + <li> + <p>A bit of indentation is done, to keep things legible</p> + </li> +</ol> + +<div class="note"><strong>注意:</strong>我们的算法符合第3点(但没有减少月份)。点1和2自动由JavaScript方法 <code><a href="/en/JavaScript/Reference/Global_Objects/JSON/stringify" title="en/JavaScript/Reference/Global_Objects/JSON/stringify">JSON.stringify()</a></code>进行管理。</div> + +<h2 id="In_summary">In summary</h2> + +<p>我们以<a href="/zh-CN/docs/Archive/JXON#Algorithm_.233.3A_a_synthetic_technique">第三种算法</a>作为<strong>最具代表性的JXON解析算法</strong>。单个结构化XML元素可能有八种不同的配置:</p> + +<ol> + <li>an empty element,</li> + <li>an element with pure text content,</li> + <li>an empty element with attributes,</li> + <li>an element with text content and attributes,</li> + <li>an element containing elements with different names,</li> + <li>an element containing elements with identical names,</li> + <li>an element containing elements and contiguous text,</li> + <li>an element containing elements and non contiguous text.</li> +</ol> + +<p>The following table shows the corresponding conversion patterns between XML and JSON according to the <a href="#Algorithm_.233.3A_a_synthetic_technique" title="Go to JXON algorithm #3">third algorithm</a>.</p> + +<table> + <thead> + <tr> + <th style="background: #faf9e2; color: #5d5636; text-align: center;"><strong>Case</strong></th> + <th style="background: #faf9e2; color: #5d5636; text-align: center;"><strong>XML</strong></th> + <th style="background: #faf9e2; color: #5d5636; text-align: center;"><strong>JSON</strong></th> + <th style="background: #faf9e2; color: #5d5636; text-align: center;"><strong>Javascript access</strong></th> + </tr> + </thead> + <tbody> + <tr> + <td style="background: #f6f6f6; color: #000000;">1</td> + <td style="background: #f6f6f6; color: #000000;"><code><animal /></code></td> + <td style="background: #f6f6f6; color: #000000;"><code>"animal": true</code></td> + <td style="background: #f6f6f6; color: #000000;"><code>myObject.animal</code></td> + </tr> + <tr> + <td style="background: #e7e5dc; color: #silver;">2</td> + <td style="background: #e7e5dc; color: #silver;"><code><animal>Deka</animal></code></td> + <td style="background: #e7e5dc; color: #silver;"><code>"animal": "Deka"</code></td> + <td style="background: #e7e5dc; color: #silver;"><code>myObject.animal</code></td> + </tr> + <tr> + <td style="background: #f6f6f6; color: #000000;">3</td> + <td style="background: #f6f6f6; color: #000000;"><code><animal name="Deka" /></code></td> + <td style="background: #f6f6f6; color: #000000;"><code>"animal": {"@name": "Deka"}</code></td> + <td style="background: #f6f6f6; color: #000000;"><code>myObject.animal["@name"]</code></td> + </tr> + <tr> + <td style="background: #e7e5dc; color: #silver;">4</td> + <td style="background: #e7e5dc; color: #silver;"><code><animal name="Deka">is my cat</animal></code></td> + <td style="background: #e7e5dc; color: #silver;"><code>"animal": { "@name": "Deka", "keyValue": "is my cat" }</code></td> + <td style="background: #e7e5dc; color: #silver;"><code>myObject.animal["@name"]</code>, <code>myObject.animal.keyValue</code></td> + </tr> + <tr> + <td style="background: #f6f6f6; color: #000000;">5</td> + <td style="background: #f6f6f6; color: #000000;"><code><animal> <dog>Charlie</dog> <cat>Deka</cat> </animal></code></td> + <td style="background: #f6f6f6; color: #000000;"><code>"animal": { "dog": "Charlie", "cat": "Deka" }</code></td> + <td style="background: #f6f6f6; color: #000000;"><code>myObject.animal.dog</code>, <code>myObject.animal.cat</code></td> + </tr> + <tr> + <td style="background: #e7e5dc; color: #silver;">6</td> + <td style="background: #e7e5dc; color: #silver;"><code><animal> <dog>Charlie</dog> <dog>Mad Max</dog> </animal></code></td> + <td style="background: #e7e5dc; color: #silver;"><code>"animal": { "dog": ["Charlie", "Mad Max"] }</code></td> + <td style="background: #e7e5dc; color: #silver;"><code>myObject.animal.dog[0]</code>, <code>myObject.animal.dog[1]</code></td> + </tr> + <tr> + <td style="background: #f6f6f6; color: #000000;">7</td> + <td style="background: #f6f6f6; color: #000000;"><code><animal> in my house <dog>Charlie</dog> </animal></code></td> + <td style="background: #f6f6f6; color: #000000;"><code>"animal": { "keyValue": "in my house", "dog": "Charlie" }</code></td> + <td style="background: #f6f6f6; color: #000000;"><code>myObject.animal.keyValue</code>, <code>myObject.animal.dog</code></td> + </tr> + <tr> + <td style="background: #e7e5dc; color: #silver;">8</td> + <td style="background: #e7e5dc; color: #silver;"><code><animal> in my ho <dog>Charlie</dog> use </animal></code></td> + <td style="background: #e7e5dc; color: #silver;"><code>"animal": { "keyValue": "in my house", "dog": "Charlie" }</code></td> + <td style="background: #e7e5dc; color: #silver;"><code>myObject.animal.keyValue</code>, <code>myObject.animal.dog</code></td> + </tr> + </tbody> +</table> + +<h2 id="Code_considerations">Code considerations</h2> + +<p>In these examples we chose to use a property named <code>keyValue</code> for the text content. The lack of standards for XML to JSON conversion leads developers to choose a variety of property names for the text content of XML <a href="/zh-CN/docs/Web/API/Element" title="Element(元素)接口是 Document的一个对象. 这个接口描述了所有相同种类的元素所普遍具有的方法和属性。 这些继承自Element并且增加了一些额外功能的接口描述了具体的行为. 例如, HTMLElement 接口是所有HTML元素的基础接口, 而 SVGElement 接口是所有SVG元素的基本接口."><code>Element</code></a> nodes that also contain other child nodes. Sometimes a property called <code>$</code> is used. Other times a property called <code>#text</code> is used (however, a name like this isn't a good choice, since the text content of a node can be parsed into a non-string value by our algorithms during the conversion). In the algorithms proposed here, you can easily change this name, depending on your needs.</p> + +<p>The choice of using a <code>true</code> value instead of a <code>null</code> value to represent empty nodes is due to the fact that <strong>when in an XML document there is an empty node the reason is often to express a<em> <code>Boolean</code></em></strong>, as in this case:</p> + +<pre class="brush: xml"><car> + <type>Ferrari</type> + <bought /> +</car> +</pre> + +<p>If the value were <code>null</code> it would be more cumbersome to launch a code like this:</p> + +<pre class="brush: js">if (myObject.car.bought) { + // do something +} +</pre> + +<div class="note"><strong>Note:</strong> According to our <a href="#Algorithm_.233.3A_a_synthetic_technique" title="Go to JXON algorithm #3">third algorithm</a> and our <a href="#Algorithm_.234.3A_a_very_minimalist_way" title="Go to JXON algorithm #4">fourth algorithm</a>, just <code>CDATASection</code> nodes which contain nothing but white spaces (precisely: <code>/^\s+$/</code>) will be parsed as <code>null</code>.</div> + +<p>The <a href="#Algorithm_.234.3A_a_very_minimalist_way" title="Go to JXON algorithm #4">fourth algorithm</a> represents a <strong>special case of conversion</strong>. As you can see, <strong>the generated JavaScript Object tree is not <a href="/en/JavaScript/Reference/Global_Objects/JSON/stringify" title="en/JavaScript/Reference/Global_Objects/JSON/stringify">stringifyable</a></strong>. It is very practical for internal JavaScript access, but don't use it if you want to transfer the tree via JSON string (as for <code><a href="/en/DOM/Worker" title="en/DOM/Worker">Worker</a></code> messages, for example).</p> + +<p>We chose to <strong>ignore nodes which have a prefix</strong> (for example: <code><ding:dong>binnen</ding:dong></code>), due to their special case (they are often used in order to represents an <a href="http://www.w3.org/TR/xmlschema-ref/" title="W3C XML Schema Definition Language (XSD): Component Designators">XML Schema</a>, which is <em>meta-information</em> concerning how to organize the <em>information</em> of the document, reserved for the XML parser). You can include them removing the string <code>&& !oNode.prefix</code> from our algorithms (by doing so the whole tag will become the property name: <code>{ "ding:dong": "binnen" }</code>).</p> + +<p>An important consideration is that, when using the <a href="#Algorithm_.233.3A_a_synthetic_technique" title="Go to JXON algorithm #3">third</a> or the <a href="#Algorithm_.234.3A_a_very_minimalist_way" title="Go to JXON algorithm #4">fourth</a> algorithm, an XML <a href="/zh-CN/docs/Web/API/Document" title="Document 接口提供了一些在浏览器服务中作为页面内容入口点而加载的一些页面,也就是 DOM 树。 DOM 树包括诸如 <body> 和 <table> 之类的元素,及其他元素。其也为文档(document)提供了全局性的函数,例如获取页面的 URL、在文档中创建新的 element 的函数。"><code>Document</code></a> can be used to create any type of JavaScript object. For example, If you want to create an object like the following:</p> + +<pre class="brush: js">{ + "myboolean": true, + "myarray": ["Cinema", "Hot dogs", false], + "myobject": { + "nickname": "Jack", + "registration_date": new Date(1995, 11, 25), + "privileged_user": true + }, + "mynumber": 99, + "mytext": "Hello World!" +} +</pre> + +<p>you must just create an XML document with the following structure:</p> + +<pre class="brush: xml"><myboolean>true</myboolean> +<myarray>Cinema</myarray> +<myarray>Hot dogs</myarray> +<myarray>false</myarray> +<myobject> + <nickname>Jack</nickname> + <registration_date>Dec 25, 1995</registration_date> + <privileged_user /> +</myobject> +<mynumber>99</mynumber> +<mytext>Hello World!</mytext> +</pre> + +<p>This example also shows how the ideal JXON document is an XML document designed specifically to be converted in JSON format, though <em>our algorithms work fine with any kind of XML document</em>.</p> + +<div class="note" id="ordering-lossless-note"><strong>Note:</strong> Despite the term JXON suggesting "lossless" conversions, these techniques are not actually lossless if one needs to preserve <strong>ordering of elements</strong>, as is common with many XML dialects (including of course <a href="/en-US/docs/XHTML" title="/en-US/docs/XHTML">XHTML</a>). The ECMAScript standard (JavaScript) indicates that object iteration order is <em>implementation dependent</em>.</div> + +<h2 id="Appendix_a_complete_bidirectional_JXON_library">Appendix: a complete, bidirectional, JXON library</h2> + +<p>Now we can create a more complete, bidirectional, JXON library based on <strong>all</strong> our algorithms (see: <a href="#Algorithm_.231.3A_a_verbose_way" title="Go to JXON algorithm #1">#1</a>, <a href="#Algorithm_.232.3A_a_less_verbose_way" title="Go to JXON algorithm #2">#2</a>, <a href="#Algorithm_.233.3A_a_synthetic_technique" title="Go to JXON algorithm #3">#3</a>, <a href="#Algorithm_.234.3A_a_very_minimalist_way" title="Go to JXON algorithm #4">#4</a>, <a href="#Reverse_algorithms" title="Reverse algorithms">reverse</a>). Its usage is modeled on the <a href="/en/JavaScript/Reference/Global_Objects/JSON" title="en/JavaScript/Reference/Global_Objects/JSON"><code>JSON</code></a> native object. <strong>Before implementing it in a working environment, please read the <a href="#const_compatibility" title="#const_compatibility">note about the <code>const</code> statement compatibility</a></strong>. The following code is also <a class="external external-icon" href="https://github.com/madmurphy/jxon.js">available on GitHub</a>.</p> + +<pre class="brush: js">"use strict"; + +/*\ +|*| +|*| JXON framework - Copyleft 2011 by Mozilla Developer Network +|*| +|*| Revision #3 - October 31th, 2016 +|*| +|*| https://developer.mozilla.org/en-US/docs/JXON +|*| https://developer.mozilla.org/User:fusionchess +|*| https://github.com/madmurphy/jxon.js +|*| +|*| This framework is released under the GNU Public License, version 3 or later. +|*| http://www.gnu.org/licenses/gpl-3.0-standalone.html +|*| +\*/ + +const JXON = new (function () { + + function parseText (sValue) { + if (rIsNull.test(sValue)) { return null; } + if (rIsBool.test(sValue)) { return sValue.toLowerCase() === "true"; } + if (isFinite(sValue)) { return parseFloat(sValue); } + if (isFinite(Date.parse(sValue))) { return new Date(sValue); } + return sValue; + } + + function EmptyTree () {} + + EmptyTree.prototype.toString = function () { return "null"; }; + + EmptyTree.prototype.valueOf = function () { return null; }; + + function objectify (vVal) { + return vVal === null ? new EmptyTree() : vVal instanceof Object ? vVal : new vVal.constructor(vVal); + } + + function createObjTree (oParentNode, nVerb, bFreeze, bNesteAttr) { + + const + nLevelStart = aCache.length, bChildren = oParentNode.hasChildNodes(), + bAttributes = oParentNode.hasAttributes && oParentNode.hasAttributes(), bHighVerb = Boolean(nVerb & 2); + + var + sProp, vContent, nLength = 0, sCollectedTxt = "", + vResult = bHighVerb ? {} : /* put here the default value for empty nodes: */ true; + + if (bChildren) { + for (var oNode, nItem = 0; nItem < oParentNode.childNodes.length; nItem++) { + oNode = oParentNode.childNodes.item(nItem); + if (oNode.nodeType === 4) { sCollectedTxt += oNode.nodeValue; } /* nodeType is "CDATASection" (4) */ + else if (oNode.nodeType === 3) { sCollectedTxt += oNode.nodeValue.trim(); } /* nodeType is "Text" (3) */ + else if (oNode.nodeType === 1 && !oNode.prefix) { aCache.push(oNode); } /* nodeType is "Element" (1) */ + } + } + + const nLevelEnd = aCache.length, vBuiltVal = parseText(sCollectedTxt); + + if (!bHighVerb && (bChildren || bAttributes)) { vResult = nVerb === 0 ? objectify(vBuiltVal) : {}; } + + for (var nElId = nLevelStart; nElId < nLevelEnd; nElId++) { + sProp = aCache[nElId].nodeName.toLowerCase(); + vContent = createObjTree(aCache[nElId], nVerb, bFreeze, bNesteAttr); + if (vResult.hasOwnProperty(sProp)) { + if (vResult[sProp].constructor !== Array) { vResult[sProp] = [vResult[sProp]]; } + vResult[sProp].push(vContent); + } else { + vResult[sProp] = vContent; + nLength++; + } + } + + if (bAttributes) { + + const + nAttrLen = oParentNode.attributes.length, + sAPrefix = bNesteAttr ? "" : sAttrsPref, oAttrParent = bNesteAttr ? {} : vResult; + + for (var oAttrib, nAttrib = 0; nAttrib < nAttrLen; nLength++, nAttrib++) { + oAttrib = oParentNode.attributes.item(nAttrib); + oAttrParent[sAPrefix + oAttrib.name.toLowerCase()] = parseText(oAttrib.value.trim()); + } + + if (bNesteAttr) { + if (bFreeze) { Object.freeze(oAttrParent); } + vResult[sAttrProp] = oAttrParent; + nLength -= nAttrLen - 1; + } + + } + + if (nVerb === 3 || (nVerb === 2 || nVerb === 1 && nLength > 0) && sCollectedTxt) { + vResult[sValProp] = vBuiltVal; + } else if (!bHighVerb && nLength === 0 && sCollectedTxt) { + vResult = vBuiltVal; + } + + if (bFreeze && (bHighVerb || nLength > 0)) { Object.freeze(vResult); } + + aCache.length = nLevelStart; + + return vResult; + + } + + function loadObjTree (oXMLDoc, oParentEl, oParentObj) { + + var vValue, oChild; + + if (oParentObj.constructor === String || oParentObj.constructor === Number || oParentObj.constructor === Boolean) { + oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toString())); /* verbosity level is 0 or 1 */ + if (oParentObj === oParentObj.valueOf()) { return; } + } else if (oParentObj.constructor === Date) { + oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toGMTString())); + } + + for (var sName in oParentObj) { + vValue = oParentObj[sName]; + if (isFinite(sName) || vValue instanceof Function) { continue; } /* verbosity level is 0 */ + if (sName === sValProp) { + if (vValue !== null && vValue !== true) { oParentEl.appendChild(oXMLDoc.createTextNode(vValue.constructor === Date ? vValue.toGMTString() : String(vValue))); } + } else if (sName === sAttrProp) { /* verbosity level is 3 */ + for (var sAttrib in vValue) { oParentEl.setAttribute(sAttrib, vValue[sAttrib]); } + } else if (sName.charAt(0) === sAttrsPref) { + oParentEl.setAttribute(sName.slice(1), vValue); + } else if (vValue.constructor === Array) { + for (var nItem = 0; nItem < vValue.length; nItem++) { + oChild = oXMLDoc.createElement(sName); + loadObjTree(oXMLDoc, oChild, vValue[nItem]); + oParentEl.appendChild(oChild); + } + } else { + oChild = oXMLDoc.createElement(sName); + if (vValue instanceof Object) { + loadObjTree(oXMLDoc, oChild, vValue); + } else if (vValue !== null && vValue !== true) { + oChild.appendChild(oXMLDoc.createTextNode(vValue.toString())); + } + oParentEl.appendChild(oChild); + } + } + + } + + /* Uncomment the following code if you want to enable the .appendJXON() method for *all* the "element" objects! */ + + /* + + Element.prototype.appendJXON = function (oObjTree) { + loadObjTree(document, this, oObjTree); + return this; + }; + + */ + + this.build = function (oXMLParent, nVerbosity /* optional */, bFreeze /* optional */, bNesteAttributes /* optional */) { + const nVerbMask = arguments.length > 1 && typeof nVerbosity === "number" ? nVerbosity & 3 : /* put here the default verbosity level: */ 1; + return createObjTree(oXMLParent, nVerbMask, bFreeze || false, arguments.length > 3 ? bNesteAttributes : nVerbMask === 3); + }; + + this.unbuild = function (oObjTree, sNamespaceURI /* optional */, sQualifiedName /* optional */, oDocumentType /* optional */) { + const oNewDoc = document.implementation.createDocument(sNamespaceURI || null, sQualifiedName || "", oDocumentType || null); + loadObjTree(oNewDoc, oNewDoc, oObjTree); + return oNewDoc; + }; + + const + sValProp = "keyValue", sAttrProp = "keyAttributes", sAttrsPref = "@", /* you can customize these values */ + aCache = [], rIsNull = /^\s*$/, rIsBool = /^(?:true|false)$/i; + +})(); +</pre> + +<div class="note" id="const_compatibility"><strong>Note:</strong> The current implementation of <a href="/en/JavaScript/Reference/Statements/const" title="en/JavaScript/Reference/Statements/const"><code>const</code></a> (constant statement) <strong>is not part of ECMAScript 5</strong>. It is supported in Firefox & Chrome (V8) and partially supported in Opera 9+ and Safari. <strong>It is not supported in Internet Explorer 6-9, or in the preview of Internet Explorer 10</strong>. <a href="/en/JavaScript/Reference/Statements/const" title="en/JavaScript/Reference/Statements/const"><code>const</code></a> is going to be defined by ECMAScript 6, but with different semantics. Similar to variables declared with the <a href="/en/JavaScript/Reference/Statements/let" title="en/JavaScript/Reference/Statements/let"><code>let</code></a> statement, constants declared with <a href="/en/JavaScript/Reference/Statements/const" title="en/JavaScript/Reference/Statements/const"><code>const</code></a> will be block-scoped. <strong>We used it only for didactic purpose. If you want a full browser compatibility of this library, please replace all the <a href="/en/JavaScript/Reference/Statements/const" title="en/JavaScript/Reference/Statements/const"><code>const</code></a> statements with the <a href="/en/JavaScript/Reference/Statements/var" title="en/JavaScript/Reference/Statements/var"><code>var</code></a> statements.</strong></div> + +<h3 id="Usage">Usage</h3> + +<p>The obtained non-native <code>JXON</code> global object will have two methods:</p> + +<table class="fullwidth-table"> + <tbody> + <tr> + <th>Method</th> + <th>Description</th> + </tr> + <tr> + <td><a href="#JXON.build_syntax" title="JXON.build"><code>JXON.build(<em>document</em>[, <em>verbosity</em>[, <em>freeze</em>[, <em>nesteAttributes</em>]]])</code></a></td> + <td>Returns a JavaScript <a href="/en/JavaScript/Reference/Global_Objects/Object" title="en/JavaScript/Reference/Global_Objects/Object"><code>Object</code></a> based on the given XML Document.</td> + </tr> + <tr> + <td><a href="#JXON.unbuild_syntax" title="JXON.unbuild"><code>JXON.unbuild(<em>objTree</em>[, <em>namespaceURI</em>[, <em>qualifiedNameStr</em>[, <em>documentType</em>]]])</code></a></td> + <td>Returns an XML <a href="/zh-CN/docs/Web/API/Document" title="Document 接口提供了一些在浏览器服务中作为页面内容入口点而加载的一些页面,也就是 DOM 树。 DOM 树包括诸如 <body> 和 <table> 之类的元素,及其他元素。其也为文档(document)提供了全局性的函数,例如获取页面的 URL、在文档中创建新的 element 的函数。"><code>Document</code></a> based on the given JavaScript <a href="/en/JavaScript/Reference/Global_Objects/Object" title="en/JavaScript/Reference/Global_Objects/Object"><code>Object</code></a>.</td> + </tr> + </tbody> +</table> + +<p>These methods are inverses of each other. So, you can work with the <code>JXON</code> object by inserting the previous code at the beginning of your scripts. If you are not interested in a bidirectional conversion, don't use it, use only one of our algotithm instead.</p> + +<p>Sample usage:</p> + +<pre class="brush: js">var myObject = JXON.build(doc); +// we got our javascript object! try: alert(JSON.stringify(myObject)); + +var newDoc = JXON.unbuild(myObject); +// we got our Document instance! try: alert((new XMLSerializer()).serializeToString(newDoc));</pre> + +<p>…the same thing using AJAX:</p> + +<pre class="brush: js">function reqListener () { + + var myObject = JXON.build(this.responseXML); + // we got our javascript object! + alert(JSON.stringify(myObject)); + + var newDoc = JXON.unbuild(myObject); + // we got our Document instance! + alert((new XMLSerializer()).serializeToString(newDoc)); + +}; + +var oReq = new XMLHttpRequest(); +oReq.onload = reqListener; +oReq.open("get", "example.xml", true); +oReq.send();</pre> + +<h4 id="JXON.build_syntax">JXON.build syntax</h4> + +<p><code>JXON.build(<a href="#JXON_build-document" title="JXON.build – @document"><em>document</em></a>[, <a href="#JXON_build-verbosity" title="JXON.build – @verbosity"><em>verbosity</em></a>[, <a href="#JXON_build-freeze" title="JXON.build – @freeze"><em>freeze</em></a>[, <a href="#JXON_build-nesteAttributes" title="JXON.build – @nesteAttributes"><em>nesteAttributes</em></a>]]])</code></p> + +<h4 id="JXON.build_description">JXON.build description</h4> + +<p>Returns a JavaScript <a href="/en/JavaScript/Reference/Global_Objects/Object" title="en/JavaScript/Reference/Global_Objects/Object"><code>Object</code></a> based on the given XML Document.</p> + +<h4 id="JXON.build_parameters">JXON.build parameters</h4> + +<dl> + <dt><code id="JXON_build-document">document</code></dt> + <dd>The XML document to be converted into JSON format.</dd> + <dt><code id="JXON_build-verbosity">verbosity</code> <span class="inlineIndicator optional optionalInline">Optional</span></dt> + <dd>The verbosity level of conversion (optional), from <code>0</code> to <code>3</code>. It is almost equivalent to our algorithms from <a href="#Algorithm_.234.3A_a_very_minimalist_way" title="Go to JXON algorithm #4">#4</a> to <a href="#Algorithm_.231.3A_a_verbose_way" title="Go to JXON algorithm #1">#1</a> (default value is <code>1</code>, which is equivalent to the <a href="#Algorithm_.233.3A_a_synthetic_technique" title="Go to JXON algorithm #3">algorithm #3</a>).</dd> + <dt><code id="JXON_build-freeze">freeze</code> <span class="inlineIndicator optional optionalInline">Optional</span></dt> + <dd>A boolean (optional) expressing whether the created object must be <a href="/en/JavaScript/Reference/Global_Objects/Object/freeze" title="en/JavaScript/Reference/Global_Objects/Object/freeze">freezed</a> or not (default value is <code>false</code>).</dd> + <dt><code id="JXON_build-nesteAttributes">nesteAttributes</code> <span class="inlineIndicator optional optionalInline">Optional</span></dt> + <dd>A boolean (optional) expressing whether the the <code>nodeAttributes</code> must be nested into a child-object named <code>keyAttributes</code> or not (default value is <code>false</code> for verbosity levels from <code>0</code> to <code>2</code>; <code>true</code> for verbosity level <code>3</code>).</dd> +</dl> + +<h4 id="JXON.unbuild_syntax">JXON.unbuild syntax</h4> + +<p><code>JXON.unbuild(<a href="#JXON_unbuild-objTree" title="JXON.unbuild – @objTree"><em>objTree</em></a>[, <a href="#JXON_unbuild-namespaceURI" title="JXON.unbuild – @namespaceURI"><em>namespaceURI</em></a>[, <a href="#JXON_unbuild-qualifiedNameStr" title="JXON.unbuild – @qualifiedNameStr"><em>qualifiedNameStr</em></a>[, <a href="#JXON_unbuild-documentType" title="JXON.unbuild – @objTree"><em>documentType</em></a>]]])</code></p> + +<h4 id="JXON.unbuild_description">JXON.unbuild description</h4> + +<p>Returns an XML Document based on the given JavaScript <a href="/en/JavaScript/Reference/Global_Objects/Object" title="en/JavaScript/Reference/Global_Objects/Object"><code>Object</code></a>.</p> + +<h4 id="JXON.unbuild_parameters">JXON.unbuild parameters</h4> + +<dl> + <dt><code id="JXON_unbuild-objTree">objTree</code></dt> + <dd>The JavaScript Object from which you want to create your XML Document.</dd> + <dt><code id="JXON_unbuild-namespaceURI">namespaceURI</code> <span class="inlineIndicator optional optionalInline">Optional</span></dt> + <dd>Is a <a href="https://developer.mozilla.org/en-US/docs/Web/API/DOMString" title="A UTF-16 String. As JavaScript already uses such strings, DOMString is mapped directly to a String."><code>DOMString</code></a> containing the namespace URI of the document to be created, or <code>null</code> if the document doesn't belong to one.</dd> + <dt><code id="JXON_unbuild-qualifiedNameStr">qualifiedNameStr</code> <span class="inlineIndicator optional optionalInline">Optional</span></dt> + <dd>Is a <a href="https://developer.mozilla.org/en-US/docs/Web/API/DOMString" title="A UTF-16 String. As JavaScript already uses such strings, DOMString is mapped directly to a String."><code>DOMString</code></a> containing the qualified name, that is an optional prefix and colon plus the local root element name, of the document to be created.</dd> + <dt><code id="JXON_unbuild-documentType">documentType</code> <span class="inlineIndicator optional optionalInline">Optional</span></dt> + <dd>Is the <a class="internal" href="https://developer.mozilla.org/En/DOM/DocumentType" title="En/DOM/DocumentType"><code>DocumentType</code></a> of the document to be created. It defaults to <code>null</code>.</dd> +</dl> + +<h3 id="Extend_the_native_Element.prototype_object">Extend the native <code><a href="/en-US/docs/Web/API/element" title="/en-US/docs/Web/API/element">Element</a>.prototype</code> object</h3> + +<p>If you want to enable the <code>.appendJXON()</code> method for all the native <a href="/en-US/docs/Web/API/element"><code>element</code></a> objects, you can uncomment the following code from the JXON library:</p> + +<pre class="brush: js"> /* Uncomment the following code if you want to enable the .appendJXON() method for *all* the "element" objects! */ + + /* + + Element.prototype.appendJXON = function (oObjTree) { + loadObjTree(document, this, oObjTree); + return this; + }; + + */</pre> + +<h4 id="Example">Example</h4> + +<p>Imagine you want to populate the following <a href="/en-US/docs/Web/API/HTMLElement"><code>HTMLElement</code></a> through JSON:</p> + +<pre class="brush: html"><div id="form_container"></div></pre> + +<p>Then, the following code:</p> + +<pre class="brush: js">document.getElementById("form_container").appendJXON({ + "form": { + "script": { + "@type": "text/javascript", + "keyValue": "\n function numbersOnly (oToCheckField, oKeyEvent) {\n return oKeyEvent.charCode === 0 || /\\d/.test(String.fromCharCode(oKeyEvent.charCode));\n }\n" + }, + "input": [{ + "@type": "hidden", + "@name": "instId", + "@value": 1234 + }, { + "@type": "hidden", + "@name": "currency", + "@value": "GBP" + }, { + "@type": "hidden", + "@name": "amount", + "@value": 0 + }, { + "@type": "hidden", + "@name": "name", + "@value": "CAPTURED" + }], + "table": { + "tr": [{ + "th": { + "@style": "text-align: right;", + "keyValue": "Product:" + }, + "td": { + "span": [{ + "input": { + "@type": "radio", + "@name": "nome", + "@id": "rel_tshirt", + "@value": "tshirt" + }, + "label": { + "@for": "rel_tshirt", + "keyValue": "T-Shirt" + }, + "@class": "product" + }, { + "input": { + "@type": "radio", + "@name": "nome", + "@id": "rel_trousers", + "@value": "trousers" + }, + "label": { + "@for": "rel_trousers", + "keyValue": "Trousers" + }, + "@class": "product" + }, { + "input": { + "@type": "radio", + "@name": "nome", + "@id": "rel_pullover", + "@value": "pullover" + }, + "label": { + "@for": "rel_pullover", + "keyValue": "Pullover" + }, + "@class": "product" + }] + } + }, { + "th": { + "@style": "text-align: right;", + "keyValue": "Quantity:" + }, + "td": { + "input": { + "@type": "text", + "@name": "myInput", + "@onkeypress": "return numbersOnly(this, event);", + "@onpaste": "return false;" + } + } + }] + }, + "p": { + "input": { + "@type": "submit", + "@value": "Purchase!" + } + }, + "@action": "https://secure-test.worldpay.com/wcc/purchase", + "@name": "BuyForm", + "@method": "POST" + } +});</pre> + +<p>will populate the previous element in the following way:</p> + +<pre class="brush: html"><div id="form_container"> + <form action="https://secure-test.worldpay.com/wcc/purchase" name="BuyForm" method="POST"> + <script type="text/javascript"> + function numbersOnly(oToCheckField, oKeyEvent) { + return oKeyEvent.charCode === 0 || /\d/.test(String.fromCharCode(oKeyEvent.charCode)); + } + </script> + <input type="hidden" name="instId" value="1234" /> + <input type="hidden" name="currency" value="GBP" /> + <input type="hidden" name="amount" value="0" /> + <input type="hidden" name="name" value="CAPTURED" /> + <table> + <tr> + <th style="text-align: right;">Product:</th> + <td><span class="product"><input type="radio" name="nome" id="rel_tshirt" value="tshirt"/><label for="rel_tshirt">T-Shirt</label></span><span class="product"><input type="radio" name="nome" id="rel_trousers" value="trousers"/><label for="rel_trousers">Trousers</label></span><span class="product"><input type="radio" name="nome" id="rel_pullover" value="pullover"/><label for="rel_pullover">Pullover</label></span> + </td> + </tr> + <tr> + <th style="text-align: right;">Quantity:</th> + <td> + <input type="text" name="myInput" onkeypress="return numbersOnly(this, event);" onpaste="return false;" /> + </td> + </tr> + </table> + <p> + <input type="submit" value="Purchase!" /> + </p> + </form> +</div></pre> + +<h3 id="Other_examples">Other examples</h3> + +<h4 id="Example_1_How_to_use_JXON_to_create_an_HTML_document_instead_of_an_XML_document">Example #1: How to use JXON to create an HTML document instead of an XML document:</h4> + +<pre class="brush: js">/* The structure of my document */ +var oMyHTMLStruct = { + "html": { + "head": { + "meta": { + "@http-equiv": "Content-Type", + "@content": "text/html; charset=UTF-8" + }, + "title": "My HTML Document", + "script": { + "@type": "text/javascript", + "keyValue": "alert(\"Welcome!\");" + }, + "style": "p:first-letter {\n font: italic bold 30px Georgia, serif;\n}" + }, + "body": { + "h1": "My HTML Document", + "p": "Hello world!!" + } + } +}; + +/* Create the document */ +var oMyHTMLDoc = JXON.unbuild(oMyHTMLStruct, "http://www.w3.org/1999/xhtml");</pre> + +<p>…And here is the output of <code>alert((new XMLSerializer()).serializeToString(oMyHTMLDoc))</code>:</p> + +<pre class="brush: html"><html> + +<head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <title>My HTML Document</title> + <script type="text/javascript"> + alert("Welcome!"); + </script> + <style> + p:first-letter { + font: italic bold 30px Georgia, serif; + } + </style> +</head> + +<body> + <h1>My HTML Document</h1> + <p>Hello world!!</p> +</body> + +</html></pre> + +<div class="note"><strong>Note:</strong> As we already said in <a href="#ordering-lossless-note">the note within <em>Code considerations</em></a>, despite the bidirectional conversion between XML and JSON <strong>is</strong> lossless regarding the whole content and the structure of an XML document, it <strong>is not</strong> lossless regarding the ordering of elements, which for some XML dialects (like XHTML) is part of the information. For instance, a bidirectional conversion of the following HTML paragraph: + +<pre class="brush: html"><p>She <strong>loves</strong> you. And definitely <strong>hates</strong> me.</p></pre> +would determine a result like the following: + +<pre class="brush: html"><p><strong>loves</strong><strong>hates</strong>Sheyou. And definitelyme.</p></pre> +As you can see in this special case, the whole information is preserved, the ordering of the elements is not.<br> +It turns out then that for some XML dialects JXON can be not the best choise, while it can be a really powerful tool in dealing with <em>standard XML</em>. One conversion method which is lossless for element order, as it relies on arrays (but, with a less human-readable, JavaScript-friendly syntax), is <a href="http://www.jsonml.org/" title="http://www.jsonml.org/">JsonML</a>.</div> + +<h3 id="About_this_library">About this library</h3> + +<p>The <code>JXON.build()</code> method summarizes all our four ways of conversion (see: <a href="#Algorithm_.231.3A_a_verbose_way" title="Go to JXON algorithm #1">#1</a>, <a href="#Algorithm_.232.3A_a_less_verbose_way" title="Go to JXON algorithm #2">#2</a>, <a href="#Algorithm_.233.3A_a_synthetic_technique" title="Go to JXON algorithm #3">#3</a>, <a href="#Algorithm_.234.3A_a_very_minimalist_way" title="Go to JXON algorithm #4">#4</a>). The result is therefore the same of our four algorithms, depending on the level of verbosity utilised. As above, optional properties and methods (commented in the example) of the <a href="#Algorithm_.231.3A_a_verbose_way" title="Go to JXON algorithm #1">first algorithm</a> (verbosity level: 3) are not included.</p> + +<p>The <code>JXON.unbuild()</code> method utilises our <a href="#Reverse_algorithms" title="Reverse algorithms">reverse algorithm</a>.</p> + +<p>Therefore, <strong>all <a href="#Code_considerations" title="Code considerations">code considerations</a> remain the same</strong>.</p> + +<h2 id="Resources">Resources</h2> + +<ul> + <li><a href="http://code.google.com/p/xml2json-xslt/wiki/TransformingRules" title="TransformingRules – xml2json-xslt">The Parker Convention</a></li> + <li><a href="http://badgerfish.ning.com/" title="BadgerFish convention">The BadgerFish Convention</a></li> + <li><a href="http://www.balisage.net/Proceedings/vol7/html/Lee01/BalisageVol7-Lee01.html" title="JXON: an Architecture for Schema and Annotation Driven JSON/XML Bidirectional Transformations – Balisage: The Markup Conference 2011">JXON: an Architecture for Schema and Annotation Driven JSON/XML Bidirectional Transformations</a></li> + <li><a href="http://www.w3.org/TR/microdata/#json">Converting HTML to other formats: JSON (The World Wide Web Consortium)</a></li> + <li><a href="http://dinogambone.com/2012/jxon-a-simple-way-to-keep-xml-out-of-your-life/" title="JXON – A simple way to keep XML out of your life – Dino Gambone's blog">JXON – A simple way to keep XML out of your life – Dino Gambone's blog</a></li> + <li><a href="http://webreflection.blogspot.it/2008/07/jxon-lossless-javascript-to-xml-object.html" title="Web Reflection: JXON – Lossless JavaScript to XML Object Notation convertion">Web Reflection: JXON – Lossless JavaScript to XML Object Notation convertion</a></li> + <li><a href="http://davidwalsh.name/convert-xml-json" title="Convert XML to JSON with JavaScript – David Walsh Blog">Convert XML to JSON with JavaScript – David Walsh Blog</a></li> + <li><a href="http://goessner.net/download/prj/jsonxml/" title="http://goessner.net/download/prj/jsonxml/">http://goessner.net/download/prj/jsonxml/</a> – just another json2xml and xml2json conversion tool</li> + <li><a href="http://tawani.blogspot.it/2006/12/serialize-javascript-objects-to-xml-for.html" title="Serialize JavaScript objects to XML (for use with Ajax) – Tawani's Blog Rants">Serialize JavaScript objects to XML (for use with Ajax) – Tawani's Blog Rants</a></li> + <li><a href="http://www.kawa.net/works/js/xml/objtree-e.html" title="XML.ObjTree – XML source code from/to JavaScript object like E4X – Kawa.net">XML.ObjTree – XML source code from/to JavaScript object like E4X – Kawa.net</a></li> + <li><a href="http://www.jsonml.org/" title="http://www.jsonml.org/">JsonML</a> – a conversion method which is lossless for element order, as it relies on arrays.</li> +</ul> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="/en/XML" title="en/XML">XML</a></li> + <li><a href="/en/JSON" title="en/JSON">JSON</a></li> + <li><a href="/en/XPath" title="en/XPath">XPath</a></li> + <li><a href="/en/E4X" title="en/E4X">E4X (ECMAScript for XML)</a></li> + <li><a href="/en/Parsing_and_serializing_XML" title="en/Parsing_and_serializing_XML">Parsing and serializing XML</a></li> + <li><a href="/en/DOM/XMLHttpRequest" title="en/XMLHttpRequest">XMLHttpRequest</a></li> + <li><a href="/en/How_to_create_a_DOM_tree" title="en/How_to_create_a_DOM_tree">How to Create a DOM tree</a></li> + <li><a href="/en/JavaScript/Introduction_to_Object-Oriented_JavaScript" title="Introduction to Object-Oriented JavaScript">Introduction to Object-Oriented JavaScript</a></li> + <li><a href="/en/JavaScript/Guide/Working_with_Objects" title="Working with Objects">Working with Objects</a></li> + <li><a href="/en/XML_Introduction" title="en/XML_Introduction">XML Introduction</a></li> +</ul> |