8

乍一看,我认为在 javascript 中使用 xml 数据就像找到一个 xml-to-json 库并将我的 xml 转换为 javascript 对象树一样简单。

但是,现在我意识到可以在 xml 中创建不直接映射到 json 的结构。

具体来说,这个:

<parentNode>
    <fooNode>data1</fooNode>
    <barNode>data2</barNode>
    <fooNode>data3</fooNode>
</parentNode>

我发现的 xml-to-json 工具将以前的转换成这样的:

{
parentnode:{
    foonode:[
        'data1',
        'data3'
    ],
    barnode:'data2'
}

}

其中,子节点的顺序发生了变化。我需要保留我的子节点的顺序。任何人都有任何比它更优雅的解决方案

a) 放弃自动转换的想法,只设计自己的 javascript 对象结构并编写代码来处理这个特定的 xml 模式

或者

b) 完全放弃任何转换的想法,将我的 xml 数据保留为 xml 文档,然后我将遍历该文档。

4

4 回答 4

4

There are established mappings from XML to JSON with limitations (see Converting Between XML and JSON) and mappings from JSON to XML (see JSONx as defined here and conversion rules by IBM). A mapping from XML to JSON that preserves order, however, has not been defined yet. To fully capture all aspects of XML, one should express the XML Infoset in JSON. if you only care about XML elements (no processing instructions, etc.), I'd choose this structure:

[
  "parentNode",
  { } /* attributes */
  [ 
    [ "fooNode", { }, [ "data1" ] ]
    [ "fooNode", { }, [ "data2" ] ]
    [ "fooNode", { }, [ "data3" ] ]
  ]
]

I implemented the same mapping as mapping between XML and Perl data structures that are just like JSON with XML::Struct. The structure further corresponds to the abstract data model of MicroXML, a simplified subset of XML.

于 2013-09-06T12:43:35.037 回答
2

如果您经常需要相同的元素名称并且您关心排序,那么使用 XML 可能会更好。您期望使用 JSON 有什么好处?

于 2009-05-12T16:33:14.463 回答
1

为什么不试试:

{ parentNode: [
  ["fooNode", "data1"],
  ["barNode", "data2"],
  ["fooNode", "data3"] ]
}

我认为它或多或少会解决问题。

是的,我认为如果它不够灵活,你应该放弃自动转换;相反,您可能会寻找使此类映射变得微不足道的 API。

于 2009-05-12T16:36:06.643 回答
0

我最近设计了这个:

(只是一个思想实验)

var someTinyInfosetSample = {
  "doctype": "html",
  "$": [
    { "": "html" },
    [ { "": "head" },
       [ { "": "title" }, "Document title" ]
    ],
    [ { "": "body" },
      [ { "": "h1" }, "Header 1" ],
      [ { "": "p", "class": "content" },
        "Paragraph... (line 1)", [ { "": "br" } ],
        "... continued (line 2)"
      ]
    ]
  ] };

(在https://jsfiddle.net/YSharpLanguage/dzq4fe39

快速理由:

XML 元素是唯一的节点类型(除了文档根),它接受混合内容(文本节点和/或其他元素、评论、PI,并定义其子节点的顺序;因此使用 JSON 数组(子索引)从 1 开始,而不是从 0 开始,因为保留索引 0 来携带节点类型(元素)信息;但是可以注意到 XPath 节点集也使用从 1 开始的索引,顺便说一句);

XML 属性名称/值映射不需要对键(属性名称)进行任何排序。它们的所有者元素,仅在该元素节点处具有唯一性;因此在容器数组的索引 0 处使用 JSON 对象(对应于所有者元素);

最后,毕竟,虽然 "" 是对象值中完全有效的 JSON 键,但 XML 元素或属性也不能有空名称……因此使用 "" 作为特殊的常规键, 提供元素名称。

下面是使用我的小型“JSLT”(在https://jsfiddle.net/YSharpLanguage/c7usrpsL/10)将其转换为 HTML 所需的内容:

var tinyInfosetJSLT = { $: [
  [ [ function/*Root*/(node) { return node.$; } ],
      function(root) { return Per(this).map(root.$); }
  ],
  [ [ function/*Element*/(node) { return { }.toString.call(node) === "[object Array]"; } ],
      function(element) {
        var children = (element.length > 1 ? element.slice(1) : null),
            startTag = element[0],
            nodeName = startTag[""],
            self = this;
        return children ?
               Per("\r\n<{stag}>{content}</{etag}>\r\n").map
               ({
                 stag: Per(this).map(startTag),
                 etag: nodeName,
                 content: Per(children).map(function(child) { return Per(self).map(child); }).join("")
               })
               :
               Per("<{stag}/>").map({ stag: Per(this).map(startTag) });
      }
  ],
  [ [ function/*StartTag*/(node) { return node[""]; } ],
      function(startTag) {
        var tag = [ startTag[""] ];
        for (var attribute in startTag) {
          if (attribute !== "") {
            tag.push
            (
              Per("{name}=\"{value}\"").
              map({ name: attribute, value: startTag[attribute].replace('"', "&quot;") })
            );
          }
        }
        return tag.join(" ");
      }
  ],
  [ [ function/*Text*/(node) { return typeof node === "string"; } ],
      function(text) {
        return text.
               replace("\t", "&x09;").
               replace("\n", "&x0A;").
               replace("\r", "&x0D;");
      }
  ]
] };

(参见https://jsfiddle.net/YSharpLanguage/dzq4fe39/1

在哪里,

Per(tinyInfosetJSLT).map(someTinyInfosetSample)

产生(作为字符串):

<html>
<head>
<title>Document title</title>
</head>

<body>
<h1>Header 1</h1>

<p class="content">Paragraph... (line 1)<br/>... continued (line 2)</p>
</body>
</html>

(但上面的转换也可以很容易地适应使用 DOM 节点工厂,并构建一个实际的 DOM 文档,而不是构建一个字符串)

'HTH,

于 2016-03-05T05:20:03.423 回答