【问题标题】:How to detect whether XML elements have child elements如何检测XML元素是否有子元素
【发布时间】:2015-09-23 06:49:36
【问题描述】:

我正在使用 CPAN XML::LibXML 模块来处理下面的 XML 数据。我需要确定每个元素是否有子元素。环顾四周,我找不到任何用于此目的的示例。

<A>
    <ts>2012</ts>
    <T>M1</T>
    <T>M2</T>
    <B>
        <id>PC</id>
        <r>10</r>
        <r>30</r>
    </B>
</A>

这是我写的 Perl 代码

#!/usr/bin/perl

use strict;
use warnings;

use XML::LibXML;

my ($x,$elname,$haschild)= ();
my $parser = XML::LibXML->new();
my $npo    = $parser->parse_file("test.xml");
my $rootel = $npo -> getDocumentElement();
$elname = $rootel -> nodeName();
print "Root name=$elname\n";

foreach $x ($rootel->childNodes) {
    $elname = $x -> nodeName();
    $haschild = $x->hasChildNodes;
    print "Child name = $elname and has child = $haschild.\n" unless ($elname =~ /#text/i);
}

虽然我使用childNodes 遍历每个节点,但我无法找到一种简单的方法来确定该节点是否有子节点。

我希望在遍历所有节点后得到结果:

A: Has children
ts: Has none
T: has none
T: has none
B: Has children
id: Has none
r: Has none
r: Has none

我得到的结果是这样的:

Root name=A
Child name = ts and has child = 1.
Child name = T and has child = 1.
Child name = T and has child = 1.
Child name = B and has child = 1.

似乎所有节点在hasChildNodes 条件检查后都返回真。

【问题讨论】:

  • 好吧,您已经获得了示例数据,但是如何发布您获得的代码,即使它还不能工作?
  • 你错了。所有这些节点都有(文本)子节点,就像 libxml 所说的那样。您显然错误地认为“节点”和“元素”的含义相同,但这是错误的。

标签: perl libxml2


【解决方案1】:

您要求的是节点的子 元素 的数量。子 节点 将包含文本和无关紧要的空白。

计算节点拥有的子元素数量的最简单方法是使用 findnodes('*')-&gt;size 作为 XPath 表达式 * 仅计算子元素。

这里有一些你描述的代码

use v5.14;
use warnings;

use XML::LibXML;

my $xml = XML::LibXML->load_xml(string => <<XML);
<A>
    <ts>2012</ts>
    <T>M1</T>
    <T>M2</T>
    <B>
        <id>PC</id>
        <r>10</r>
        <r>30</r>
    </B>
</A>
XML

my $nodes = $xml->findnodes('//*');
foreach my $node ($nodes->get_nodelist) {
  my $children;
  for ($node->findnodes('*')->size) {
    $children = 'none' when 0;
    $children = '1 child' when 1;
    default { $children = "$_ children" }
  }
  printf "%s: has %s\n", $node->localname, $children;
}

输出

A: has 4 children
ts: has none
T: has none
T: has none
B: has 3 children
id: has none
r: has none
r: has none

【讨论】:

    【解决方案2】:

    hasChildNodes 方法呢?

    use XML::LibXML;
    my $xml = XML::LibXML->createDocument;
    $xml->setDocumentElement($xml->createElement('root'));
    $xml->documentElement->addChild($xml->createElement('son'));
    for my $node ($xml->documentElement,
                  $xml->documentElement->firstChild) {
        print $node->hasChildNodes, "\n";
    }
    

    打印

    1
    0
    

    请记住,文本节点也是子节点(即节点和元素是不同的概念)。

    【讨论】:

      【解决方案3】:

      如果您只需要知道子节点是否存在,那么测试:

      $node-&gt;exists('*')

      会比:

      $node-&gt;findnodes('*')-&gt;size

      因为一旦找到第一个节点,它就会退出。

      【讨论】:

        猜你喜欢
        • 2014-11-15
        • 1970-01-01
        • 2022-12-16
        • 2020-02-21
        • 1970-01-01
        • 1970-01-01
        • 2011-04-20
        • 2011-04-14
        • 2011-01-10
        相关资源
        最近更新 更多