我最近设计了这个:
(只是一个思想实验)
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('"', """) })
);
}
}
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,