Xml 已解决:XPath:循环通过没有子节点和子节点的节点
我使用XML::LibXML在perl中导入了一个XML文件。生成的XPath结构有几个节点。有些有孩子,有些没有。如何在没有子节点的所有节点之间循环,然后在有子节点的所有节点之间循环? 致以最良好的祝愿,丹尼尔 编辑:更多细节-2020-11-11 10:10 亲爱的,对不起,我的坏,我需要在这里更准确。 另外:新手提醒(以防你还没有注意到) 用例 我正在编写一个perl脚本,它将读取OneWire网关。几个传感器连接到网关。perl脚本从网关读取XML数据。XML数据包含网关的数据(如连接了多少设备、一个计数器和多个读数)。XML数据中还提供了每个连接传感器的读数(温度、湿度等) XML数据 下面是一个XML的示例。我把它缩短了。读数的数量和传感器的数量可能会有所不同:Xml 已解决:XPath:循环通过没有子节点和子节点的节点,xml,perl,xpath,xml-libxml,Xml,Perl,Xpath,Xml Libxml,我使用XML::LibXML在perl中导入了一个XML文件。生成的XPath结构有几个节点。有些有孩子,有些没有。如何在没有子节点的所有节点之间循环,然后在有子节点的所有节点之间循环? 致以最良好的祝愿,丹尼尔 编辑:更多细节-2020-11-11 10:10 亲爱的,对不起,我的坏,我需要在这里更准确。 另外:新手提醒(以防你还没有注意到) 用例 我正在编写一个perl脚本,它将读取OneWire网关。几个传感器连接到网关。perl脚本从网关读取XML数据。XML数据包含网关的数据(如连接了
<?xml version="1.0" encoding="UTF-8"?>
<Devices-Detail-Response xmlns="http://www.embeddeddatasystems.com/schema/owserver" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<PollCount>1069</PollCount>
<DevicesConnected>1</DevicesConnected>
<LoopTime>1.630</LoopTime>
<owd_DS18B20 Description="Programmable resolution thermometer">
<Name>DS18B20</Name>
<Family>28</Family>
<ROMId>60000003BDE03828</ROMId>
<Health>0</Health>
<Channel>1</Channel>
<RawData>000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000</RawData>
<PrimaryValue>0.0000 Deg C</PrimaryValue>
<Temperature Units="Centigrade">0.0000</Temperature>
<UserByte1 Writable="True">0</UserByte1>
<UserByte2 Writable="True">0</UserByte2>
<Resolution>9</Resolution>
<PowerSource>0</PowerSource>
</owd_DS18B20>
<owd_DS18B20 Description="Programmable resolution thermometer">
<Name>DS18B20</Name>
<Family>28</Family>
<ROMId>73000003BDD96528</ROMId>
<Health>0</Health>
<Channel>1</Channel>
<RawData>000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000</RawData>
<PrimaryValue>0.0000 Deg C</PrimaryValue>
<Temperature Units="Centigrade">0.0000</Temperature>
<UserByte1 Writable="True">0</UserByte1>
<UserByte2 Writable="True">0</UserByte2>
<Resolution>9</Resolution>
<PowerSource>0</PowerSource>
</owd_DS18B20>
<owd_DS2423 Description="RAM with counters">
<Name>DS2423</Name>
<Family>1D</Family>
<ROMId>100000000FCB421D</ROMId>
<Health>0</Health>
<Channel>1</Channel>
<RawData>000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000</RawData>
<PrimaryValue>0, 0</PrimaryValue>
<Counter_A>0</Counter_A>
<Counter_B>0</Counter_B>
</owd_DS2423>
<owd_DS2423 Description="RAM with counters">
<Name>DS2423</Name>
<Family>1D</Family>
<ROMId>F10000000F88251D</ROMId>
<Health>0</Health>
<Channel>1</Channel>
<RawData>000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000</RawData>
<PrimaryValue>0, 0</PrimaryValue>
<Counter_A>0</Counter_A>
<Counter_B>0</Counter_B>
</owd_DS2423>
</Devices-Detail-Response>
为什么要更改它?
我希望有一种更通用的方法,而不预先指定我期望的节点(基本上省略两个qw数组)
我希望这一点现在更清楚了。感谢您的帮助!
致以最良好的祝愿,丹尼尔
编辑:这里有一个似乎很有效的解决方案:
#!/usr/bin/env perl
use warnings;
use strict;
use autodie;
use feature 'say';
use XML::LibXML;
use XML::LibXML::XPathContext;
use Readonly;
Readonly my $url => 'details.xml'; # This is the XML file
#Readonly my $url => 'http://192.168.0.73/details.xml';
my $xmlns = 'http://www.embeddeddatasystems.com/schema/owserver';
Readonly my $ns => 'ow';
say "My source is $url";
my $dom = eval {
XML::LibXML->load_xml(location => $url);
};
if($@) {
# Log failure and exit
say "Error parsing $url";
say "$@";
say 'I will exit now.';
exit 0;
}
say "XML::LibXML has read $url";
#say $dom;
say '';
my $xpath = XML::LibXML::XPathContext->new($dom);
$xpath->registerNs($ns, $xmlns);
say 'Process xpath doc in a nested loop';
say 'Outer loop: to iterate through all nodes with children (i.e. parents).';
say 'Inner loop: loop through the found parents and filter for children that have no children themselves.';
foreach my $node ($xpath->findnodes("//$ns:*[count(*)>0]")) { # only parents are found
say $node->localname;
foreach my $child ($node->findnodes("*[count(*)=0]")) { # parents are excluded
next if ($child->localname eq 'RawData');
say ' ' . $child->localname . ' = ' . $child->to_literal;
}
}
say'';
请编辑你的问题,并提供一个最小的可复制的例子。我们真的应该看到一些细节。你能发布这样一个文件的简短示例和你拥有的代码(工作与否)吗?
/*[count(*)>0]
和/*[count(*)=0]
,我想。但是,这只查找作为元素的子元素。这是//子元素::*
还是只查找终端节点?请澄清。好的,我自己找到了解决办法。//*[count(*)>0]表达式为我指明了正确的方向。我已经将我的新代码包含在我的提问中。请编辑您的问题并提供一个最小的可复制示例。我们真的应该看到一些细节。你能发布这样一个文件的简短示例和你拥有的代码(工作与否)吗?/*[count(*)>0]
和/*[count(*)=0]
,我想。但是,这只查找作为元素的子元素。这是//子元素::*
还是只查找终端节点?请澄清。好的,我自己找到了解决办法。//*[count(*)>0]表达式为我指明了正确的方向。我已经在我的questoin中包含了我的新代码。
#!/usr/bin/env perl
use warnings;
use strict;
use autodie;
use feature 'say';
use XML::LibXML;
use XML::LibXML::XPathContext;
use Readonly;
Readonly my $url => 'details.xml'; # This is the XML file
#Readonly my $url => 'http://192.168.0.73/details.xml';
my $xmlns = 'http://www.embeddeddatasystems.com/schema/owserver';
Readonly my $ns => 'ow';
say "My source is $url";
my $dom = eval {
XML::LibXML->load_xml(location => $url);
};
if($@) {
# Log failure and exit
say "Error parsing $url";
say "$@";
say 'I will exit now.';
exit 0;
}
say "XML::LibXML has read $url";
#say $dom;
say '';
my $xpath = XML::LibXML::XPathContext->new($dom);
$xpath->registerNs($ns, $xmlns);
say 'Process xpath doc in a nested loop';
say 'Outer loop: to iterate through all nodes with children (i.e. parents).';
say 'Inner loop: loop through the found parents and filter for children that have no children themselves.';
foreach my $node ($xpath->findnodes("//$ns:*[count(*)>0]")) { # only parents are found
say $node->localname;
foreach my $child ($node->findnodes("*[count(*)=0]")) { # parents are excluded
next if ($child->localname eq 'RawData');
say ' ' . $child->localname . ' = ' . $child->to_literal;
}
}
say'';