【问题标题】:xml to json mapping challengexml 到 json 映射挑战
【发布时间】:2010-10-25 14:48:19
【问题描述】:

乍一看,我认为在 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 文档,然后我将对其进行遍历。

【问题讨论】:

  • 当您将 XML 转换为 JSON 时,为什么顺序很重要? “节点顺序”不是 XML 特定的问题吗?

标签: javascript xml json mapping format-conversion


【解决方案1】:

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

【讨论】:

  • 您可以更改 dom 节点的行为以使您的生活更轻松。或者你可以把它包起来。
【解决方案2】:

为什么不试试:

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

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

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

【讨论】:

  • 这也是我可能会做的,除了我可能更喜欢:{ parentNode: [ { key: val }, ... ], ... } 而不是 2 元素数组。
【解决方案3】:

已经建立了从 XML 到 JSON 的映射(参见 Converting Between XML and JSON)和从 JSON 到 XML 的映射(参见 JSONx 为 defined hereconversion rules by IBM)。但是,尚未定义从 XML 到 JSON 的保留顺序的映射。要完全捕获 XML 的所有方面,应该用 JSON 表示 XML Infoset。如果您只关心 XML 元素(没有处理指令等),我会选择这种结构:

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

我实现了与 XML 和 Perl 数据结构之间的映射相同的映射,就像带有XML::Struct 的 JSON。该结构进一步对应于MicroXML的抽象数据模型,是XML的简化子集。

【讨论】:

  • 我不得不偶然发现这个问题以及您阅读有关 MicroXML 的好答案。有趣的是,我们经常需要独立地解决相同的问题和/或类似的解决方案。对如何启用 XML 到 JSON(反之亦然)往返很感兴趣,我最终想出了这样的东西:jsfiddle.net/YSharpLanguage/an3hdz64/1
【解决方案4】:

我最近设计了这个:

(只是一个思想实验)

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 元素是唯一接受混合内容(文本节点和/或其他元素、cmets、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)

yields(作为字符串):

<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,

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-25
    • 2012-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-03
    • 2014-04-17
    • 2021-12-28
    相关资源
    最近更新 更多