xml2js: comment est la sortie?
j'essaie d'utiliser le noeud.js module xml2js
Mon code est assez simple:
function testparse(pathname, callback) {
var parser = require('xml2js').Parser(),
util = require('util'),
fs = require('fs'),
fs.readFile(pathname, function (err, data) {
parser.parseString(data, function(err, result) {
console.log('Complete result:');
console.log(util.inspect(result, {depth: null})); //Work
console.log('Try to access element:');
console.log(result.smil.body); //Work
console.log(result.smil.body.update); //Undefined
});
});
}
Mon fichier xml:
<?xml version="1.0"?>
<smil>
<head/>
<body>
<update /*some field*//>
<stream name="name"/>
<playlist /*some field*/>
<video /*some field*//>
<video /*some field*//>
<video /*some field*//>
</playlist>
</body>
</smil>
La sortie de me donner:
Complete result:
{ smil:
{ head: [''],
body:
[ { update: [[Object]],
stream: [[Object]],
playlist: [[Object]] } ] } }
Try to access element:
[Object]
Undefined
j'ai réussi à accéder à body en essayant, mais maintenant je suis coincé, y a-t-il un modèle ou un exemple de comment xml2js produit le xml analysé quelque part?
6 réponses
xml2js a une tâche non enviable: convertir XML en JSON d'une manière qui peut être inversée, sans connaître le schéma à l'avance. Il semble évident, au premier abord:
<name>Fred</name> → { name: "Fred" }
<chacha /> → { chacha: null }
facile jusqu'ici, non? Comment à ce sujet, si?
<x><y>z</y><x>
Suppression de l'humain noms conviviaux conduit à la maison de l'incertitude face à xml2js
. À première, vous pourriez penser que c'est tout à fait raisonnable:
{ x: { y: "z" } }
plus tard, vous trébuchez sur ce texte XML et réalisez votre deviné-dans le schéma est faux:
<x><y>z</y><y>z2</y></x>
Uh oh. Peut-être qu'on aurait dû utiliser un tableau. Au moins tous les membres ont la même étiquette:
{ x: [ "z", "z2" ] }
Inévitablement, cependant, qui s'avère être à courte vue:
<x><y>z</y><y>z2</y><m>n</m>happy</x>
Euh...
{ x: [ { y: "z" }, { y : "z2" }, { m: "n" }, "happy" ] }
... et puis quelqu'un vous polit avec quelques attributs et des espaces de noms XML.
la façon de construire un schéma de sortie plus concis vous semble évidente. Vous pouvez déduire les détails de l'étiquette et les noms d'attributs. Vous le comprenez.
la bibliothèque ne partage pas ce point de vue.
si la bibliothèque ne connaît pas le schéma, elle doit soit "utiliser et abuser" des tableaux, des couches supplémentaires d'objets, des noms d'attributs spéciaux, ou les trois.
la seule alternative est d'employer un schéma de sortie variable. Cela rend les choses simples au début, comme nous l'avons vu plus haut, mais vous vous trouverez rapidement à écrire beaucoup de code conditionnel. Examinons ce qui se passe si les enfants portant le même nom d'étiquette sont regroupés dans une liste, mais seulement s'il y en a plus d'une:
if (Array.isArray(x.y)) {
processTheYChildren(x.y);
} else if (typeof(x.y) === 'object') {
// only one child; construct an array on the fly because my converter didn't
processTheYChildren([x.y]);
} else ...
TL;DR: c'est plus difficile qu'il n'y paraît. Lire L'Open311 Conversion JSON et XML pour plus de détails sur les autres JSON côté des représentations. Tous les tableaux" use and abuse", les couches supplémentaires d'objets, les membres avec des noms qui n'apparaissent pas dans le XML original, ou les trois.
les états de documentation de xml2js, vous pouvez configurer l'analyseur pour ne pas abuser des tableaux, en définissant la propriété explicitArray
false
(important: il doit être une valeur booléenne que la chaîne de caractères "false"
travail!)
Exemple:
var parser = new xml2js.Parser({explicitArray : false});
de cette façon, vous devriez être en mesure d'accéder à vos propriétés JSON d'une manière beaucoup plus facile. J'espère que cela aide quelqu'un.
le JSON qui revient n'est pas très JavaScript. J'ai écrit une fonction d'assistance qui peuvent rendre plus facile de travailler avec.
assurez-vous de le lire avant de l'utiliser pour comprendre ce qu'il fait.
xml.parseString(xmlString, function(err, results){
if(err) throw err
results = cleanXML(results);
});
var cleanXML = function(xml){
var keys = Object.keys(xml),
o = 0, k = keys.length,
node, value, singulars,
l = -1, i = -1, s = -1, e = -1,
isInt = /^-?\s*\d+$/,
isDig = /^(-?\s*\d*\.?\d*)$/,
radix = 10;
for(; o < k; ++o){
node = keys[o];
if(xml[node] instanceof Array && xml[node].length === 1){
xml[node] = xml[node][0];
}
if(xml[node] instanceof Object){
value = Object.keys(xml[node]);
if(value.length === 1){
l = node.length;
singulars = [
node.substring(0, l - 1),
node.substring(0, l - 3) + 'y'
];
i = singulars.indexOf(value[0]);
if(i !== -1){
xml[node] = xml[node][singulars[i]];
}
}
}
if(typeof(xml[node]) === 'object'){
xml[node] = cleanXML(xml[node]);
}
if(typeof(xml[node]) === 'string'){
value = xml[node].trim();
if(value.match(isDig)){
if(value.match(isInt)){
if(Math.abs(parseInt(value, radix)) <= Number.MAX_SAFE_INTEGER){
xml[node] = parseInt(value, radix);
}
}else{
l = value.length;
if(l <= 15){
xml[node] = parseFloat(value);
}else{
for(i = 0, s = -1, e = -1; i < l && e - s <= 15; ++i){
if(value.charAt(i) > 0){
if(s === -1){
s = i;
}else{
e = i;
}
}
}
if(e - s <= 15){
xml[node] = parseFloat(value);
}
}
}
}
}
}
return xml;
};
Exemples:
{
queries: { query: [ {}, {}, {} ] }
}
devient
{
queries: [ {}, {}, {} ]
}
et
{
types: { type: [ {}, {}, {} ] }
}
devient
{
types: [ {}, {}, {} ]
}
Il sera également en toute sécurité convertissez les entiers / points flottants.
Modifier: Remplacé pour... avec pour
Pour ceux qui se demandent, xml2js l'utilisation et l'abus de tableau
Pour mon fichier, l'arbre serait:
.result //Object
|_.head //Array
|_.body //Array
|_.update //Array
| |_.$ //Object
| |_.fields //Strings
|
|_.stream //Array
| |_.$ //Object
| |_.fields //Strings
|
|_.playlist //Array
|_.$ //Object
|_.fields //Strings
|
|_.video //Array
|_.$ //Object
|_.fields //Strings
Vous voudrez peut-être essayer console.log(util.inspect(result, false, null))
, qui devrait afficher l'ensemble du résultat.
Pour moi, c'était une console.question dir ou plus précisément une non-question.
j'ai eu le même résultat quand je console.dir la sortie:
{
TextView: [ [Object] ],
ImageView: [ [Object] ] } }
Mais j'ai été surpris de découvrir que c'était une console.dir limitation et les données étaient effectivement là. Apparemment console.dir ne montre pas plus de quelques niveaux. Quand j'ai de la console.dir un niveau plus profond, les données y était:
console.log(result.RelativeLayout.TextView);
sortie:
{ '$':
{ 'android:layout_width': 'wrap_content',
'android:layout_height': 'wrap_content',
'android:layout_marginLeft': '10dp',
'android:layout_marginTop': '10dp',
'android:textColor': '#ffffff',
'android:id': '@+id/textView',
'android:text': 'Hello World!' } }
j'ai commencé à chercher d'autres libs seulement pour aller en arrière et essayer à nouveau. Si ça aide quelqu'un hourra.