【问题标题】:solved: Perl: XML::LibXML does not parse this XML document [duplicate]已解决:Perl:XML::LibXML 不解析此 XML 文档 [重复]
【发布时间】:2021-02-26 19:26:49
【问题描述】:

我(新手警报)在解析 XML 文档中的信息时遇到问题。我有一个设备 (called OW-SERVER) 从 1wire 传感器网络读取传感器值并在 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>
<DevicesConnectedChannel1>1</DevicesConnectedChannel1>
<DevicesConnectedChannel2>0</DevicesConnectedChannel2>
<DevicesConnectedChannel3>0</DevicesConnectedChannel3>
<DataErrorsChannel1>1</DataErrorsChannel1>
<DataErrorsChannel2>0</DataErrorsChannel2>
<DataErrorsChannel3>0</DataErrorsChannel3>
<VoltageChannel1>4.87</VoltageChannel1>
<VoltageChannel2>4.88</VoltageChannel2>
<VoltageChannel3>4.78</VoltageChannel3>
<VoltagePower>5.09</VoltagePower>
<DeviceName>OWServer_v2-Enet</DeviceName>
<HostName>EDSOWSERVER2</HostName>
<MACAddress>00:04:A3:F8:5F:FE</MACAddress>
<DateTime>2020-10-24 19:27:08</DateTime>
<owd_DS18B20 Description="Programmable resolution thermometer">
<Name>DS18B20</Name>
<Family>28</Family>
<ROMId>3E000005A0472628</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>A4000005A0EC8128</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>69000005A0046128</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>B0000005A00F2528</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>D80000000FD6C41D</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>ED0000000FC5741D</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>B90000001013E31D</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>830000000F97DB1D</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_DS18B20 Description="Programmable resolution thermometer">
<Name>DS18B20</Name>
<Family>28</Family>
<ROMId>0004175171AFFF28</ROMId>
<Health>7</Health>
<Channel>1</Channel>
<RawData>57014B467FFF0C1038FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000</RawData>
<PrimaryValue>21.4375 Deg C</PrimaryValue>
<Temperature Units="Centigrade">21.4375</Temperature>
<UserByte1 Writable="True">75</UserByte1>
<UserByte2 Writable="True">70</UserByte2>
<Resolution>12</Resolution>
<PowerSource>255</PowerSource>
</owd_DS18B20>
</Devices-Detail-Response>

我想使用 XML::LibXML 来读取每个单独传感器的值。但是,下面的 perl 脚本并不成功:

#!/usr/perl/bin

use warnings;
use strict;
use autodie;
use feature 'say';
use XML::LibXML;

my $file = 'doc.xml';

my $dom = eval {
    XML::LibXML->load_xml(location => $file);
};
if($@) {
    # Log failure and exit
    say "Error parsing $url";
    say "$@";
    say 'I will exit now.';
    exit 0;
}

say 'XML::LibXML has read the following:';
say $dom;

say '';
say 'Looking for Sensors:';
foreach my $sensor ($dom->findnodes('//owd_DS18B20')) {
    say 'found one!';
    say $sensor->to_literal();
}

任何帮助将不胜感激。 丹尼尔

【问题讨论】:

  • “不成功”是什么意思?
  • foreach 循环没有打印出它找到了一个传感器。
  • 我玩弄了一点 XML::LibXML,我现在的主要理论是 XML::LibXML 无法解析结构。每个传感器都包含在 之间的块中。每个 DS18B20 传感器的描述完全相同。 XML::LibXML 似乎对此有疑问。

标签: xml perl xml-libxml 1wire


【解决方案1】:

问题是使用默认命名空间而没有给它一个名称以在查询中使用。

来自findnodesXML::LibXML::Node 文档:

关于 XPath 的一个常见错误是假设节点测试由一个没有前缀的元素名称组成,与默认命名空间中的元素匹配。这个假设是错误的 - 根据 XPath 规范,这样的节点测试只能匹配不在(即 null)命名空间中的元素。

命名空间,尤其是默认的命名空间,如果没有一些工作,XPath 就不能很好地发挥作用。

使用XML::LibXML::XPathContext 并为命名空间分配名称是建议的方法之一。像这样:

#!/usr/bin/env perl
use warnings;
use strict;
use autodie;
use feature 'say';
use XML::LibXML;
use XML::LibXML::XPathContext;

my $file = 'doc.xml';

my $dom = eval {
    XML::LibXML->load_xml(location => $file);
};
if($@) {
    # Log failure and exit
    say "Error parsing $file";
    say "$@";
    say 'I will exit now.';
    exit 0;
}

say 'XML::LibXML has read the following:';
say $dom;

say '';
say 'Looking for Sensors:';
my $xpath = XML::LibXML::XPathContext->new($dom);
$xpath->registerNs("ow", "http://www.embeddeddatasystems.com/schema/owserver");
foreach my $sensor ($xpath->findnodes('//ow:owd_DS18B20')) {
    say 'found one!';
    say $sensor->to_literal();
}

【讨论】:

  • 您好,Shawn,非常感谢,现在可以使用了!你刚刚做了五一……
  • @synaps-o-dan 随时。不要忘记接受答案以将其标记为已解决。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-04
  • 2010-12-15
  • 1970-01-01
  • 1970-01-01
  • 2020-07-10
相关资源
最近更新 更多