2009-05-12 8 views
4

À première vue, je pensais que l'utilisation de données XML en javascript serait aussi simple que de trouver une bibliothèque xml-to-json et de transformer mon xml en un arbre d'objets javascript.Défi de mappage xml à json

Maintenant, cependant, je me rends compte qu'il est possible de créer des structures en XML qui ne correspondent pas directement à JSON.

Plus précisément, ce:

<parentNode> 
    <fooNode>data1</fooNode> 
    <barNode>data2</barNode> 
    <fooNode>data3</fooNode> 
</parentNode> 

Les outils xml-à-JSON que j'ai trouvé convertir la précédente à quelque chose comme ceci:

{ 
parentnode:{ 
    foonode:[ 
     'data1', 
     'data3' 
    ], 
    barnode:'data2' 
} 

}

dans lequel, la l'ordre des nœuds enfants a été modifié. J'ai besoin de préserver l'ordre de mes nœuds enfants. Quelqu'un at-il une solution qui est plus élégante que

a) l'abandon de l'idée de la conversion automatique et juste conception de ma propre structure de l'objet javascript et écrire du code pour gérer ce schéma XML spécifique

ou

b) l'abandon de la idée de toute conversion, et en laissant mes données XML comme un document XML que je vais ensuite traverser.

+0

Pourquoi l'ordre importe quand vous avez converti le XML en JSON? L'ordre des nœuds n'est-il pas spécifique à XML? – Cerebrus

Répondre

2

Si vous avez souvent besoin du même nom d'élément et que vous vous souciez de commander, il est préférable de conserver XML. Quels avantages attendez-vous de l'utilisation de JSON?

+1

Seulement que c'est plus facile de travailler avec javascript. – morgancodes

+0

Vous pouvez changer le comportement des nœuds dom pour vous faciliter la vie. Ou vous pourriez l'envelopper. –

1

Pourquoi ne pas essayer:

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

Je pense qu'il serait plus ou moins résoudre le problème.

Et oui, je pense que vous devriez abandonner la conversion automatique si elle n'est pas assez flexible; à la place, vous pouvez rechercher une API qui rend ces mappages triviaux.

+1

C'est ce que je ferais probablement aussi, sauf que je pourrais préférer: '{parentNode: [{key: val}, ...], ...}' plutôt que 2 tableaux d'éléments. – rfunduk

2

Il est créé à partir de correspondances XML JSON avec des limitations (voir Converting Between XML and JSON) et les correspondances de JSON à XML (voir JSONx comme defined here et conversion rules by IBM). Un mappage de XML vers JSON qui conserve l'ordre n'a cependant pas encore été défini. Pour capturer complètement tous les aspects de XML, il faut exprimer le XML Infoset dans JSON. si vous ne vous préoccupez des éléments XML (sans instructions de traitement, etc.), je choisirais cette structure:

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

I mis en œuvre la même cartographie que la cartographie entre les structures de données XML et Perl qui sont comme JSON avec XML::Struct . La structure correspond en outre au modèle de données abstrait de MicroXML, un sous-ensemble simplifié de XML.

+1

J'ai dû trébucher sur cette question et votre bonne réponse à lire sur MicroXML. C'est drôle comment nous arrivons souvent avec le besoin de résoudre les mêmes problèmes et/ou avec des solutions similaires, indépendamment. Intrigué par la façon d'activer le formatage XML vers JSON (et vice versa), j'ai finalement trouvé quelque chose comme ceci: https://jsfiddle.net/YSharpLanguage/an3hdz64/1 – YSharp

0

Je FORMULEES cela, récemment:

(juste une expérience de pensée)

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)

justification rapide:

éléments XML sont le seul type de noeud (à côté de la racine du document) qui accepte le contenu mixte (nœuds de texte et/ou d'autres éléments, commentaires, PI, et définit un ordre de ses nœuds enfants, d'où le e des tableaux JSON (les index enfants étant alors basés sur 1, au lieu de 0, en raison de l'index réservé 0 pour porter le type de nœud (élément) info; mais on peut noter que les nodesets XPath utilisent aussi un index basé sur 1, btw);

Les cartes de nom/valeur d'attribut XML n'ont pas besoin d'être classées par ordre (noms d'attribut) par rapport à. leur élément propriétaire, uniquement l'unicité de ceux de ce nœud d'élément; d'où l'utilisation d'un objet JSON à l'index 0 du tableau conteneur (correspondant à l'élément owner); Après tout, alors que "" est une clé JSON parfaitement valide dans les valeurs d'objet, il est également vrai que ni les éléments XML ni les attributs ne peuvent avoir un nom vide de toute façon ... d'où l'utilisation de "" en tant que clé spéciale spéciale, pour fournir le nom de l'élément.

Et voici ce qu'il faut pour le transformer en HTML en utilisant mon petit "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('"', "&quot;") }) 
      ); 
      } 
     } 
     return tag.join(" "); 
     } 
    ], 
    [ [ function/*Text*/(node) { return typeof node === "string"; } ], 
     function(text) { 
     return text. 
       replace("\t", "&x09;"). 
       replace("\n", "&x0A;"). 
       replace("\r", "&x0D;"); 
     } 
    ] 
] }; 

(Cf. https://jsfiddle.net/YSharpLanguage/dzq4fe39/1)

où,

Per(tinyInfosetJSLT).map(someTinyInfosetSample) 

donne (sous forme de chaîne):

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

(mais surtout la transformation pourrait également être facilement adapté pour utiliser une usine de nœud DOM, et de construire un document DOM réel, au lieu de construire une chaîne)

« HTH,