2011-08-12 60 views
4

我使用perl的XML :: LibXML模块来解析来自设备的XML响应。 看来,我可以成功获取数据的唯一方法是通过修改设备的XML响应。 下面是从设备我的XML响应:使用perl XML :: LibXML来解析

<chassis-inventory xmlns="http://xml.juniper.net/junos/10.3D0/junos-chassis"> 

<chassis junosstyle="inventory"> 

<name>Chassis</name> 

<serial-number>JN111863EAFF</serial-number> 

<description>VJX1000</description> 

<chassis-module> 

<name>Midplane</name> 

</chassis-module> 

<chassis-module> 

<name>System IO</name> 

</chassis-module> 

<chassis-module> 

<name>Routing Engine</name> 

<description>VJX1000</description> 

<chassis-re-disk-module> 

<name>ad0</name> 

<disk-size>1953</disk-size> 

<model>QEMU HARDDISK</model> 

<serial-number>QM00001</serial-number> 

<description>Hard Disk</description> 

</chassis-re-disk-module> 

</chassis-module> 

<chassis-module> 

<name>FPC 0</name> 

<chassis-sub-module> 

<name>PIC 0</name> 

</chassis-sub-module> 

</chassis-module> 

<chassis-module> 

<name>Power Supply 0</name> 

</chassis-module> 

</chassis> 

</chassis-inventory> 

这里是我使用的解析,找到例如序列号的Perl代码:

#!/bin/env perl 
use strict; 
use warnings; 
use XML::LibXML; 
my $f = ("/var/working/xmlstuff"); 
sub yeah { 
my $ff; 
my $f = shift; 
open(my $fff,$f); 
while(<$fff>) { 
$_ =~ s/^\s+$//; 
$_ =~ s/^(<\S+)\s.*?=.*?((?:\/)?>)/$1$2/g; 
$ff .= $_; 
} 
close($fff); 
return $ff 
} 
my $tparse = XML::LibXML->new(); 
my $ss = $tparse->load_xml(string => &yeah($f)); 
print map $_->to_literal,$ss->findnodes('/chassis-inventory/chassis/serial-number'); 

如果我不使用正则表达式替换没有为脚本加载解析。 我能理解换行符的剥离,但为什么我必须删除从XML响应的属性,所以它只能出现这些线条:

<chassis-inventory xmlns="http://xml.juniper.net/junos/10.3D0/junos-chassis"> 

<chassis junosstyle="inventory"> 

成为这样的:

<chassis-inventory> 
<chassis> 
  1. 这是XML响应还是XML :: LibXML模块的问题?

  2. 有没有办法让它忽略文件中没有使用正则表达式替换的空行的事实?

感谢您的帮助。

+0

我相信这可能会失败,因为您的XML缺少正确的标头和文档类型。也就是说,这看起来很简单,你可以尝试使用XML :: Simple,即使XML不是100%正确的,也可以设置为解析。 – Cfreak

回答

12

XPATH表达式失败的原因是因为命名空间;你需要在上下文中搜索。下面是来自XML::libXML documentation的解释:

注记的命名空间和XPATH:

有关XPath的一个常见的错误是假设由元素名称的 在默认 命名空间没有前缀匹配元素节点测试。这个假设是错误的 - 通过XPath规范,例如 节点测试只能匹配名称空间中没有(即空) 的元素。

因此,例如,不能用$节点 - 一个XHTML 文件的根元素>找到(“/ HTML”),因为“/ HTML”比赛将只有 根元素没有命名空间匹配,但所有XHTML元素 都属于命名空间http://www.w3.org/1999/xhtml。 (请注意, xmlns =“...”名称空间声明也可以在DTD中指定, 这会使情况更糟糕,因为如果没有默认名称空间,XML文档看起来为 )。

要解决这个问题,请注册命名空间,然后使用命名空间搜索您的文档。下面是一个适用于您的示例:

#!/bin/env perl 
use strict; 
use warnings; 
use XML::LibXML; 

my $xml = XML::LibXML->load_xml(location => '/var/working/xmlstuff'); 
my $xpc = XML::LibXML::XPathContext->new($xml); 
$xpc->registerNs('x', 'http://xml.juniper.net/junos/10.3D0/junos-chassis'); 

foreach my $node ($xpc->findnodes('/x:chassis-inventory/x:chassis/x:serial-number')) { 

    print $node->textContent() . "\n"; 
} 
+1

感谢您的解释和解决方案。 – salparadise