xml2js:输出如何?

我试图使用node.js模块xml2js

我的代码很简单:

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

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

输出给我:

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

我已经成功通过尝试访问正文,但现在我卡住了,有没有模板或xml2js如何输出parsingXML的例子?

xml2js有一个令人羡慕的任务:将XML转换为JSON,这种方式可以颠倒过来,而不必事先知道模式。 起初似乎很明显:

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

到目前为止,对吗? 不过呢?

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

删除人类友好的名字驱动着xml2js面临的不确定性。 起初,你可能会认为这是相当合理的:

 { x: { y: "z" } } 

后来,你浏览这个XML文本,并意识到你的猜测 – 架构是错误的:

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

呃哦。 也许我们应该使用一个数组。 至less所有的成员都有相同的标签:

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

然而,不可避免的是,这似乎是短视的:

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

呃…

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

…然后有人用一些属性和XML命名空间抛光你。

构build更简洁的输出模式的方法对您来说是显而易见的。 您可以从标签和属性名称中推断出详细信息。 你明白了

图书馆不同意这种理解。

如果库不知道模式,它必须“使用和滥用”数组,额外的对象层,特殊的属性名称,或所有三个。

唯一的select是使用可变输出模式。 正如我们上面看到的那样,这样可以保持简单,但是很快你会发现自己写了大量的条件代码。 考虑如果具有相同标签名称的孩子被折叠到列表中,但是只有多于一个:

 if (Array.isArray(xy)) { processTheYChildren(xy); } else if (typeof(xy) === 'object') { // only one child; construct an array on the fly because my converter didn't processTheYChildren([xy]); } else ... 

TL; DR:比看起来更难。 阅读Open311的JSON和XML转换页面,了解其他JSON端表示的细节。 所有“使用和滥用”数组,额外的对象层,名称未出现在原始XML中的成员,或全部三个。

正如xml2js的文档所述,通过将属性explicitArray设置为false (重要的:它必须是布尔值,因为string"false"将不起作用!),您可以configurationparsing器不滥用数组。

例:

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

这样,您应该能够以更简单的方式访问您的JSON属性。 我希望这可以帮助任何人。

返回的JSON不太适合JavaScript。 我写了一个帮助函数,可以使它更容易处理。

在使用它之前一定要阅读它,这样你才能明白它的作用。

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

例子:

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

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

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

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

它也将安全地转换整数/浮点数。

编辑:replace为…用于

对于那些想知道的,xml2js使用和滥用数组

对于我的文件,树会是:

 .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 

对我来说这是一个console.dir问题,或者更准确地说是一个非问题。

当我console.dir输出时,我有相同的结果:

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

但是我惊讶地发现这是一个console.dir限制,数据实际上在那里。 显然console.dir不会显示更多的级别。 当我更深层次的调查时,数据在那里:

  console.log(result.RelativeLayout.TextView); 

输出:

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

我开始寻找其他libs只能回去,再试一次。 如果它帮助任何人欢呼。

也许我误解了这个问题,但我想你可能想要尝试console.log(util.inspect(result, false, null)) ,它应该显示整个结果。