Недавно я разработал это:
(просто мысленный эксперимент)
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 не требуется упорядочивать ключи (имена атрибутов) по сравнению с. их владелец элемента, только уникальность тех на этом элементе узла; следовательно, использование объекта JSON с индексом 0 массива контейнера (соответствует элементу owner);
и, наконец, в конце концов, хотя "" является совершенно допустимым ключом JSON в значениях объектов, это также тот случай, когда ни элементы XML, ни атрибуты не могут иметь пустое имя в любом случае ... следовательно, использование "" в качестве специального , обычный ключ, для предоставления имени элемента.
И вот что нужно, чтобы превратить его в HTML, используя мой маленький "JSLT" (на https://jsfiddle.net/YSharpLanguage/c7usrpsL/10):
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 вместо построения строки)
НТН,