NodeJS xml2js:输出结果如何?

fjaof16o  于 2023-05-06  发布在  Node.js
关注(0)|答案(6)|浏览(165)

我正在尝试使用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

我已经通过尝试成功地访问了body,但现在我被卡住了,有没有一个模板或例子说明xml2js如何在某处输出解析后的xml?

fhity93d

fhity93d1#

TL;DR

比看起来难多了。阅读Open 311 JSON and XML Conversion页面,了解其他JSON端表示的详细信息。它们都“滥用”数组、额外的对象层、名称没有出现在原始XML中的成员,或者三者都有。

长应答

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>

也许我们应该用数组。至少所有成员都有相同的标签:

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

然而,这不可避免地被证明是短视的:

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

呃...

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

...然后有人用一些属性和XML名称空间来修饰您。
构造更简洁的输出模式的方法对您来说是显而易见的。可以从标记和属性名称推断详细信息。你懂的
图书馆不同意这种理解。
如果库不知道模式,它必须“使用和滥用”数组、额外的对象层、特殊的属性名,或者三者都使用。
唯一的选择是采用可变输出模式。这使它一开始很简单,正如我们上面看到的,但是您很快就会发现自己编写了大量的条件代码。考虑一下,如果具有相同标签名称的子标签被折叠到一个列表中会发生什么,但只有当有多个子标签时才会发生:

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

nhhxz33t2#

正如xml 2 js的文档所述,您可以通过将属性explicitArray设置为false(重要信息:它必须是一个布尔值,因为字符串"false"将只是工作!)
示例:

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

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

exdqitrt

exdqitrt3#

返回的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: [ {}, {}, {} ]
}

它还可以安全地转换整数/浮点数。

  • 编辑:替换为…in with for*
44u64gxh

44u64gxh4#

对于那些想知道的人,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
vojdkbi0

vojdkbi05#

您可能想尝试console.log(util.inspect(result, false, null)),它应该显示整个结果。

mzaanser

mzaanser6#

对我来说,这是一个console.dir问题,或者更准确地说,是一个非问题。
当我console.dir输出时,我得到了相同的结果:

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

但我惊讶地发现,这是一个console.dir限制,数据实际上是存在的。显然console.dir没有显示超过几个级别。当我控制.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,只是回去再试一次。如果这能帮助任何人欢呼。

相关问题