Javascript xml到json映射挑战
乍一看,我认为在javascript中使用xml数据就像查找xml到json库并将xml转换为javascript对象树一样简单 然而,现在我意识到可以用xml创建不直接映射到json的结构 具体而言,这:Javascript xml到json映射挑战,javascript,xml,json,mapping,format-conversion,Javascript,Xml,Json,Mapping,Format Conversion,乍一看,我认为在javascript中使用xml数据就像查找xml到json库并将xml转换为javascript对象树一样简单 然而,现在我意识到可以用xml创建不直接映射到json的结构 具体而言,这: <parentNode> <fooNode>data1</fooNode> <barNode>data2</barNode> <fooNode>data3</fooNode> <
<parentNode>
<fooNode>data1</fooNode>
<barNode>data2</barNode>
<fooNode>data3</fooNode>
</parentNode>
}
其中,子节点的顺序已更改。我需要保留子节点的顺序。任何人都有比这更优雅的解决方案
a) 放弃自动转换的想法,只需设计自己的javascript对象结构并编写代码来处理这个特定的xml模式
或
b) 完全放弃任何转换的想法,将我的xml数据作为xml文档,然后我将遍历它。如果您经常需要相同的元素名称,并且关心排序,那么最好还是使用xml。使用JSON有什么好处?为什么不试试:
{ parentNode: [
["fooNode", "data1"],
["barNode", "data2"],
["fooNode", "data3"] ]
}
我认为这或多或少会解决这个问题
是的,我认为如果自动转换不够灵活,你应该放弃它;相反,您可能会寻找一个使此类映射变得微不足道的API。有一些已建立的从XML到JSON的映射,但有一些限制(请参阅),还有从JSON到XML的映射(请参阅JSONx as和)。然而,还没有定义从XML到JSON的映射来保持顺序。要完全捕获XML的所有方面,应该用JSON表示XML。如果您只关心XML元素(没有处理指令等),我会选择以下结构:
[
"parentNode",
{ } /* attributes */
[
[ "fooNode", { }, [ "data1" ] ]
[ "fooNode", { }, [ "data2" ] ]
[ "fooNode", { }, [ "data3" ] ]
]
]
我实现了与XML和Perl数据结构之间的映射相同的映射,这些数据结构与JSON相同。该结构进一步对应于XML的一个简化子集的抽象数据模型。我最近设计了这个: (只是一个思维实验) (at) 快速理由: XML元素是唯一接受混合内容(文本节点和/或其他元素、注释、PI)的节点类型(除了文档根),并定义其子节点的顺序;因此使用JSON数组(子索引基于1,而不是基于0,因为保留索引0携带节点类型(元素)信息;但可以注意到XPath节点集也使用基于1的索引(顺便说一句) XML属性名/值映射不需要对键(属性名)wrt.owner元素进行任何排序,只需要该元素节点上键的唯一性;因此在容器数组的索引0处使用JSON对象(对应于owner元素) 最后,毕竟,虽然“”是对象值中完全有效的JSON键,但XML元素或属性也不能有空名称……因此使用“”作为特殊的常规键来提供元素名称 下面是使用我的小“JSLT”(at)将其转换为HTML的步骤: 收益率(作为字符串):
文件标题
标题1
段落(第1行)
续(第2行)
(但是上面的转换也可以很容易地调整为使用DOM节点工厂,并构建实际的DOM文档,而不是构建字符串)
“HTH,当您将XML转换为JSON时,为什么顺序很重要?难道“节点顺序”不是XML特有的问题吗?您可以更改dom节点的行为以使您的生活更轻松。或者您可以将其包装。这也是我可能会做的,但我可能更喜欢:
{parentNode:[{key:val},…}
而不是2元素数组。我不得不偶然发现这个问题和你的好答案来阅读MicroXML。有趣的是,我们经常需要独立地解决相同的问题和/或类似的解决方案。对如何将XML转换为JSON(反之亦然)感兴趣往返,我最终想到了这样的东西:
[
"parentNode",
{ } /* attributes */
[
[ "fooNode", { }, [ "data1" ] ]
[ "fooNode", { }, [ "data2" ] ]
[ "fooNode", { }, [ "data3" ] ]
]
]
var someTinyInfosetSample = {
"doctype": "html",
"$": [
{ "": "html" },
[ { "": "head" },
[ { "": "title" }, "Document title" ]
],
[ { "": "body" },
[ { "": "h1" }, "Header 1" ],
[ { "": "p", "class": "content" },
"Paragraph... (line 1)", [ { "": "br" } ],
"... continued (line 2)"
]
]
] };
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('"', """) })
);
}
}
return tag.join(" ");
}
],
[ [ function/*Text*/(node) { return typeof node === "string"; } ],
function(text) {
return text.
replace("\t", "&x09;").
replace("\n", "&x0A;").
replace("\r", "&x0D;");
}
]
] };
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>