将xml文件中具有相同名称的标记与其他xml文件中的其他标记进行比较

时间:2017-03-17 13:15:05

标签: xml perl xml-parsing

我有两个XML文件。在第一个我有一些已经在DB中的设备(标签 ipAddress 很重要)。 第二个XML文件包含设备/设备,如果它们不在DB(Post请求),则应添加这些设备/设备。

如果两个XML文件只有一个设备(一个带有ipAddress的标签),我已经有了比较两个XML文件的代码。

FILE1(包含30个设备。例如我只添加了2个。)

<?xml version="1.0" ?>
 <queryResponse last="34" first="0" count="35" type="Devices" responseType="listEntityInstances" requestUrl="https://hostname/webacs/api/v1/data/Devices?.full=true" rootUrl="https://hostname/webacs/api/v1/data">
  <entity dtoType="devicesDTO" type="Devices" url="https://hostname/webacs/api/v1/data/Devices/200">
     <devicesDTO displayName="201200" id="200">
       <deviceName>NEW</deviceName>
       <deviceType>Cisco Switch</deviceType>
       <ipAddress>10.66.12.128</ipAddress>
     </devicesDTO>
   </entity>
   <entity dtoType="devicesDTO" type="Devices" url="https://hostname/webacs/api/v1/data/Devices/201">
     <devicesDTO displayName="201201" id="201">
       <deviceName>NEW-SWW</deviceName>
       <deviceType>Cisco Switch</deviceType>
       <ipAddress>10.66.12.127</ipAddress>
     </devicesDTO>
   </entity>
 </queryResponse>

FILE2(可能是一个或多个设备)

<?xml version="1.0"?>
  <devicesImport>
    <devices>
      <device>
         <ipAddress>10.66.0.8</ipAddress>
         <networkMask>24</networkMask>
        <snmpWriteCommunity>labor</snmpWriteCommunity>
      <udfs>
         <udf>
            <name>LaborTest</name>
         </udf>
      </udfs>
   </device>
  </devices>
  </devicesImport>
   <devicesImport>
    <devices>
      <device>
         <ipAddress>10.66.0.9</ipAddress>
         <networkMask>24</networkMask>
        <snmpWriteCommunity>labor</snmpWriteCommunity>
      <udfs>
         <udf>
            <name>LaborTest</name>
         </udf>
      </udfs>
   </devices>
  </devices>
 </devicesImport>

我的代码:

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


 my $xml1 = XML::Twig->new->parsefile('FILE1.xml');
 my $xml2 = XML::Twig->new->parsefile('FILE2.xml');

 #$xml2->findnodes( './ipAddress/*'); # I tried to cover all ipAddress from FILE1

  #Next Try to do it other way
  #foreach $xml1->get_xpath( '//ipAddress', 0 )->text {
  #foreach $xml2->get_xpath( '//ipAddress', 0 )->text {


    # I compare here just one tag from both files (it works if my file contains just one device)
    if ( $xml1->get_xpath( '//ipAddress', 0 )->text
    eq $xml2->get_xpath( '//ipAddress', 0 )->text ) 

   {
     print "IP matches\n";
   }

我也试过

    if (( $xml1->get_xpath( '//ipAddress', 0 )->text
    eq $xml2->get_xpath( '//ipAddress', 0 )->text ) 
    for $xml2->findnodes  ('//ipAddress'));

但它不起作用。

1 个答案:

答案 0 :(得分:2)

好的,所以这里的事情是get_xpath找到符合特定条件的节点。

如果您确实以相同的顺序获得了内容,则可以获得两个get_xpath响应列表并对其进行迭代。

但我不认为XML中的安全假设 - 设备可能会丢失。

相反,你需要写一个search - get_xpath也可以这样做。

您的输入存在一些问题 - FILE1.xml您已经到达那里,实际上是两个单独的XML文档。两者之间没有root标记,并且<?xml声明两次。

所以你需要稍微改造它以使它成为一个单独的doc(或单独解析)。与FILE2.xml类似,您在结尾处有两个</devices>标记(一个应为</device>)。检查您是否使用了有效的XML,因为如果您不这样做,各种各样的事情都会破坏:

但为了便于说明,我假设他们是单个文件:

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

my $xml1 = XML::Twig->new->parsefile('FILE1.xml');
my $xml2 = XML::Twig->new->parsefile('FILE2.xml');

foreach my $device ( $xml2->get_xpath('//device') ) {
   my $ip_addr = $device->first_child_text('ipAddress');
   print "Looking for $ip_addr\n";
   if ( my $search = $xml1->get_xpath("//ipAddress[string()=\"$ip_addr\"]") )
   {
      print "Found: ", $search->parent->first_child_text('deviceName'), "\n";
   }
   else {
      print "Didn't find match for: ",
        $device->get_xpath( './/name', 0 )->text, "\n";
   }
}

现在,这里找不到任何内容,因为您的IP在两个文件中不匹配。

XML::Twigxpath的功能有限制,因此值得检查quick reference guide(这就是XML :: LibXML进入其中的地方&#39;自己 - 它的功能更全面)