Вызов карт XML от JSON
На первый взгляд, я подумал, что использовать данные xml в javascript будет так же просто, как найти библиотеку 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'
}
}
в котором порядок дочерних узлов был изменен. Мне нужно сохранить порядок моих дочерних узлов. У любого есть более элегантное решение, чем
а) отказаться от идеи автоматического преобразования и просто спроектировать собственную структуру объектов javascript и написать код для обработки этой конкретной XML-схемы
или же
б) отказаться от идеи какого-либо преобразования вообще и оставить мои данные XML в виде документа XML, который я затем перейду.
4 ответа
Существуют установленные сопоставления из XML в JSON с ограничениями (см. " Преобразование между XML и JSON") и сопоставления из JSON в XML (см. JSONx, как определено здесь, и правила преобразования IBM). Однако отображение из XML в JSON, сохраняющее порядок, еще не определено. Чтобы полностью охватить все аспекты XML, нужно выразить XML Infoset в формате JSON. если вы заботитесь только об элементах XML (без инструкций по обработке и т. д.), я бы выбрал следующую структуру:
[
"parentNode",
{ } /* attributes */
[
[ "fooNode", { }, [ "data1" ] ]
[ "fooNode", { }, [ "data2" ] ]
[ "fooNode", { }, [ "data3" ] ]
]
]
Я реализовал то же отображение, что и отображение между структурами данных XML и Perl, которые похожи на JSON с XML:: Struct. Структура также соответствует абстрактной модели данных MicroXML, упрощенного подмножества XML.
Если вам часто нужно одно и то же имя элемента, и вы хотите упорядочить его, возможно, лучше остаться с XML. Какие преимущества вы ожидаете от использования JSON?
Почему бы не попробовать:
{ parentNode: [
["fooNode", "data1"],
["barNode", "data2"],
["fooNode", "data3"] ]
}
Я думаю, что это более или менее решит проблему.
И да, я думаю, вам следует отказаться от автоматического преобразования, если оно недостаточно гибкое; вместо этого вы можете искать API, который делает такие отображения тривиальными.
Я разработал это недавно:
(просто мысленный эксперимент)
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 вместо построения строки)
"НТН,