해결됨 : Perl : XML :: LibXML이이 XML 문서를 구문 분석하지 않음 [중복]
Nov 15 2020
나는 (초보자 경고) XML 문서에서 정보를 구문 분석하는 데 문제가 있습니다. 1wire 센서 네트워크에서 센서 값을 읽고 XML 문서에서 판독 값을 제공 하는 장치 ( OW-SERVER라고 함 )가 있습니다. 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();
}
어떤 도움을 주시면 감사하겠습니다. 다니엘
답변
1 Shawn Nov 15 2020 at 11:46
문제는 쿼리에서 사용할 이름을 지정하지 않고 기본 네임 스페이스를 사용하는 것입니다.
로부터 XML :: LibXML :: 노드 에 대한 설명서 findnodes
:
XPath에 대한 일반적인 실수는 접두사가없는 요소 이름으로 구성된 노드 테스트가 기본 네임 스페이스의 요소와 일치한다고 가정하는 것입니다. 이 가정은 잘못된 것입니다. XPath 사양에 따라 이러한 노드 테스트는 네임 스페이스가없는 (즉 널) 네임 스페이스에있는 요소 만 일치시킬 수 있습니다.
네임 스페이스, 특히 기본 네임 스페이스와 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();
}