2012-05-28 91 views
2

我使用CPAN XML::LibXML模块来处理下面的XML数据。我需要确定每个元素是否有子元素。在我周围搜索找不到任何用于此目的的例子。如何检测XML元素是否有子元素

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

这是Perl代码我写havae

#!/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后返回true状态检查。

+1

嗯,你已经得到的样本数据,但如何张贴你有代码,尽管它还没有工作? – cjm

+0

你错了。所有这些节点都有(文本)子节点,就像libxml所说的那样。你显然错误地认为“节点”和“元素”意味着相同的东西,但这是错误的。 – ikegami

回答

3

怎么样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 

请记住,文本节点是一个子节点,太(即节点和单元是不同的概念)。

5

你所要求的是孩子的元素节点的数量。子节点节点将包括文本和无意义的空白。

计算节点具有的子元素数量的最简单方法是使用findnodes('*')->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 
1

如果你只需要知道,如果随后的子节点存在测试:

$node->exists('*')

会效率比:

$node->findnodes('*')->size

,因为它会作为第一个节点被发现后立即退出。

相关问题