xml2json xml2js vue nodejs node library example convert xml node.js xml-parsing

vue - xml2js: ¿cómo es la salida?



xml2js node (6)

Estoy tratando de usar el módulo node.js xml2js

Mi código es bastante 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 }); }); }

Mi archivo xml es como:

<?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 salida me da:

Complete result: { smil: { head: [''''], body: [ { update: [[Object]], stream: [[Object]], playlist: [[Object]] } ] } } Try to access element: [Object] Undefined

He tenido éxito en el acceso al cuerpo al intentarlo, pero ahora estoy atascado, ¿hay alguna plantilla o ejemplo de cómo xml2js genera el xml analizado en alguna parte?


Para mí fue un problema de console.dir o más exactamente no problemático.

Tuve el mismo resultado cuando console.dir el resultado:

{ TextView: [ [Object] ], ImageView: [ [Object] ] } }

Pero me sorprendió descubrir que era una limitación de console.dir y la información estaba realmente allí. Aparentemente console.dir no muestra más que unos pocos niveles. Cuando console.dir un nivel más profundo, los datos estaban allí:

console.log(result.RelativeLayout.TextView);

salida:

{ ''$'': { ''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!'' } }

Empecé a buscar otras libs solo para volver y volver a intentarlo. Si ayuda a alguien, ¡hurra!


Para aquellos que se preguntan, xml2js uso y abuso de array

Para mi archivo, el árbol sería:

.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


xml2js tiene una tarea poco envidiable: convertir XML a JSON de forma que se pueda revertir, sin conocer el esquema de antemano. Parece obvio, al principio:

<name>Fred</name> → { name: "Fred" } <chacha /> → { chacha: null }

Fácil hasta ahora, ¿verdad? ¿Qué tal esto, sin embargo?

<x><y>z</y><x>

La eliminación de los nombres amigables para los seres humanos lleva a casa la incertidumbre que enfrenta xml2js . Al principio, podrías pensar que esto es bastante razonable:

{ x: { y: "z" } }

Más tarde, se tropieza con este texto XML y se da cuenta de que su esquema de adivinación era incorrecto:

<x><y>z</y><y>z2</y></x>

UH oh. Tal vez deberíamos haber usado una matriz. Al menos todos los miembros tienen la misma etiqueta:

{ x: [ "z", "z2" ] }

Inevitablemente, sin embargo, eso resulta ser corto de miras:

<x><y>z</y><y>z2</y><m>n</m>happy</x>

Uh ...

{ x: [ { y: "z" }, { y : "z2" }, { m: "n" }, "happy" ] }

... y luego alguien lo pulirá con algunos atributos y espacios de nombres XML.

La forma de construir un esquema de salida más conciso te parece obvia. Puede inferir detalles de la etiqueta y los nombres de los atributos. Tú lo entiendes.

La biblioteca no comparte esa comprensión.

Si la biblioteca no conoce el esquema, debe "usar y abusar" de matrices, capas adicionales de objetos, nombres de atributos especiales o los tres.

La única alternativa es emplear un esquema de salida variable. Eso lo mantiene simple al principio, como vimos anteriormente, pero rápidamente te encontrarás escribiendo una gran cantidad de código condicional. Considere lo que sucede si los niños con el mismo nombre de etiqueta se colapsan en una lista, pero solo si hay más de uno:

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: es más difícil de lo que parece. Lea la página de Conversión JSON y XML de Open311 para obtener detalles de otras representaciones del lado JSON. Todas las matrices de "uso y abuso", capas adicionales de objetos, miembros con nombres que no aparecían en el XML original, o los tres.


Como dice la documentación de xml2js , puede configurar el analizador para no abusar de las matrices, estableciendo la propiedad explicitArray en false (importante: tiene que ser un valor booleano ya que la cadena "false" simplemente no funcionará).

Ejemplo:

var parser = new xml2js.Parser({explicitArray : false});

De esta manera, debería poder acceder a sus propiedades JSON de una manera mucho más fácil. Espero que esto ayude a cualquiera.


El JSON que vuelve no es demasiado amigable para JavaScript. He escrito una función de ayuda que puede facilitar el trabajo.

Asegúrese de leerlo antes de usarlo para que pueda entender lo que hace.

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

Ejemplos:

{ queries: { query: [ {}, {}, {} ] } }

se convierte

{ queries: [ {}, {}, {} ] }

y

{ types: { type: [ {}, {}, {} ] } }

se convierte

{ types: [ {}, {}, {} ] }

También convertirá con seguridad enteros / puntos flotantes.

Editar: reemplazado por ... con con por


Tal vez estoy malinterpretando la pregunta, pero creo que es posible que desee probar console.log(util.inspect(result, false, null)) , que debe mostrar el resultado completo.