【问题标题】:How to list XML node attributes with XML::LibXML?如何使用 XML::LibXML 列出 XML 节点属性?
【发布时间】:2014-11-07 07:34:30
【问题描述】:

给定以下 XML sn-p:

<outline>
  <node1 attribute1="value1" attribute2="value2">
    text1
  </node1>
</outline>

我如何得到这个输出?

outline
node1=text1
node1 attribute1=value1
node1 attribute2=value2

我查看了use XML::LibXML::Reader;,但该模块似乎只提供对其名称引用的属性values的访问。以及我首先如何获得属性名称列表?

【问题讨论】:

    标签: xml perl attr xml-libxml


    【解决方案1】:

    这样的事情应该可以帮助你。

    您的问题尚不清楚&lt;outline&gt; 是数据的根元素,还是隐藏在更大文档中的某个地方。还不清楚您希望解决方案有多通用-例如您想以这种方式转储整个文档吗?

    无论如何,这个程序以相当简洁的方式从给定的 XML 输入中生成您请求的输出。

    use strict;
    use warnings;
    use 5.014;     #' For /r non-destructive substitution mode
    
    use XML::LibXML;
    
    my $xml = XML::LibXML->load_xml(IO => \*DATA);
    
    my ($node) = $xml->findnodes('//outline');
    
    print $node->nodeName, "\n";
    
    for my $child ($node->getChildrenByTagName('*')) {
      my $name = $child->nodeName;
    
      printf "%s=%s\n", $name, $child->textContent =~ s/\A\s+|\s+\z//gr;
    
      for my $attr ($child->attributes) {
        printf "%s %s=%s\n", $name, $attr->getName, $attr->getValue;
      }
    }
    
    __DATA__
    <outline>
      <node1 attribute1="value1" attribute2="value2">
        text1
      </node1>
    </outline>
    

    输出

    outline
    node1=text1
    node1 attribute1=value1
    node1 attribute2=value2
    

    【讨论】:

      【解决方案2】:

      你可以通过$e-&gt;findnodes( "./@*");找到属性列表

      下面是一个解决方案,它使用纯 XML::LibXML,而不是 XML::LibXML::Reader,它适用于您的测试数据。不过,它可能对额外的空白和混合内容很敏感,因此在使用之前先在真实数据上进行测试。

      #!/usr/bin/perl
      
      use strict;
      use warnings;
      
      use XML::LibXML;
      
      my $dom= XML::LibXML->load_xml( IO => \*DATA);
      my $e= $dom->findnodes( "//*");
      
      foreach my $e (@$e)
        { print $e->nodeName;
      
          # text needs to be trimmed or line returns show up in the output
          my $text= $e->textContent;
          $text=~s{^\s*}{};
          $text=~s{\s*$}{};
      
          if( ! $e->getChildrenByTagName( '*') && $text)
            { print "=$text"; }
          print "\n"; 
      
          my @attrs= $e->findnodes( "./@*");
          # or, as suggested by Borodin below, $e->attributes
      
          foreach my $attr (@attrs)
            { print $e->nodeName, " ", $attr->nodeName. "=", $attr->value, "\n"; }
        }
      __END__
      <outline>
        <node1 attribute1="value1" attribute2="value2">
          text1
        </node1>
      </outline>
      

      【讨论】:

      • 有更简洁的方法来获取属性。显而易见的是my @attrs = $e-&gt;attributes,它返回所有属性节点的列表,但元素节点对象也表现为绑定哈希引用,keys %$e 将返回所有属性名称,而$e-&gt;{attr_name} 将返回属性值attr_name.
      • 谢谢,我在文档中没有找到这个,我觉得这很奇怪。现在我在“重载”下看到了它,呵呵!我仍然没有看到attributes,至少在XML::LibXML::Element的文档中是这样的
      • 我明白了,我没想到会在那里找到它。实际上,这根本没有意义。我看到它还用于返回与节点关联的命名空间声明列表,WTF?为什么 1 种方法可以得到 2 种截然不同的结果?我什至在 DOM 规范中都找不到它……我很高兴我使用 XML::Twig ;--)
      • XML::LibXML::ElementXML::LibXML::Node 之间的边界有点奇怪。我希望所有属性都出现在前者中,因为没有其他节点类型可以具有属性。但是命名空间声明还不错:命名空间看起来就像一个名为 xmlns 的属性。
      • 同意,确实使用findnodes( "./@*")(IR 使用%$e)您不会获得命名空间声明,而attributes 会将它们提供给您。在测试之前,我认为attributes 会返回一个应用于节点的所有命名空间声明的列表,而不仅仅是在元素的开始标记中声明的那些。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-19
      • 2020-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多