【问题标题】:xml2js: how is the output?xml2js:输出如何?
【发布时间】:2013-12-12 20:38:42
【问题描述】:

我正在尝试使用 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 如何在某处输出解析的 xml?

【问题讨论】:

    标签: xml node.js xml-parsing


    【解决方案1】:

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

    【讨论】:

    • 感谢@BhargavRao 的编辑,这让我更满意这是一个答案。
    【解决方案2】:

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

    我在 console.dir 输出时得到了相同的结果:

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

    但我惊讶地发现这是一个 console.dir 限制并且数据实际上在那里。显然,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!' } }
    

    我开始寻找其他库只是为了回去再试一次。如果它帮助任何人欢呼。

    【讨论】:

      【解决方案3】:

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

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

      编辑:将 for... 替换为 for

      【讨论】:

        【解决方案4】:

        作为xml2js' documentation states,您可以通过将属性explicitArray 设置为false 来配置解析器以不滥用数组(重要:它必须是一个布尔值,因为字符串"false" 将只是工作!)

        例子:

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

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

        【讨论】:

        • 如果你使用它,你现在必须检查你是否真的收到了一个元素或一个元素数组。否则,您的代码中可能会出现类型灾难。
        • 我用过这个然后就可以了:var Parser = require('xml2js-parser') var parser = new Parser({explicitArray:false, mergeAttrs : true});
        • 感谢@Rohitluthra mergeAttrs : true,救了我
        【解决方案5】:

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

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

        【讨论】:

        • 很好的答案,甚至是稍后。
        • 你把 TL;DR 放在最后是不是在逗我? :)
        【解决方案6】:

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

        【讨论】:

        • ……而且,更好的是,它实际上回答了这个问题。我没有提供模板或示例。 :)
        猜你喜欢
        • 1970-01-01
        • 2021-10-07
        • 2018-04-07
        • 2018-08-17
        • 1970-01-01
        • 2017-06-13
        • 1970-01-01
        • 2017-01-06
        • 2017-01-29
        相关资源
        最近更新 更多