如何比较不同XML文档中的某些值? [英] How do I compare certain values from different XML documents?

查看:65
本文介绍了如何比较不同XML文档中的某些值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想用Perl编写比较两个XML文件的代码.

I want to write code in Perl that compares two XML files.

历史的一点点... 使用API​​文档(获取请求),我从Web Service1获得data1,从Service2获得data2.它们以XML格式显示,但不一样.

A Little bit from the history... With API Documentation (get request) I get data1 form the Web Service1 and data2 from the Service2. They are presented in XML Format, but not the same.

我应该比较这两个文件(deviceName和ipAddress)中的仅两个元素,如果两个文件中的元素相同,则应该是一条消息"WebService1已经包含DeviceName"Switch1".如果没有,我将发出POST请求,并将此设备添加到WebService1/WebService2中.

I should compare just two elements in these files (deviceName and ipAddress), if they are the same in both files, It should be a message " WebService1 already contains DeviceName "Switch1" ". If not - I would make POST request and add this device in WebService1/WebService2.

您能给我建议,我应该使用哪些模块,以及应该如何进行比较呢?

Can you give me advice, what Modules should I use and how should I begin with this comparing?

例如(文件1)

   <?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/201">
         <devicesDTO displayName="201201" id="201">
           <clearedAlarms>0</clearedAlarms>
           <collectionDetail></collectionDetail>
           <collectionTime></collectionTime>
           <creationTime></creationTime>
           <criticalAlarms>0</criticalAlarms>
           <deviceId>205571</deviceId>
           <deviceName>NEW-SW5</deviceName>
           <deviceType>Cisco Switch</deviceType>
           <informationAlarms>0</informationAlarms>
           <ipAddress>10.66.12.128</ipAddress>
         <location></location>
           <majorAlarms>0</majorAlarms>
           <managementStatus></managementStatus>
              <manufacturerPartNrs>
                  <manufacturerPartNr></manufacturerPartNr>
              </manufacturerPartNrs>
              <minorAlarms>0</minorAlarms>
              <productFamily></productFamily>
              <reachability>Reachable</reachability>
              <softwareType>IOS</softwareType>
              <softwareVersion>12.1(22)</softwareVersion>
              <warningAlarms>0</warningAlarms>
         </devicesDTO>
      </entity>
   </queryResponse>

File2

  <?xml version="1.0" encoding="utf-8" standalone="yes"?>
  <ns3:networkdevice name="NEW-SW5" id="9a6ef750-2620-11e4-81be-b83861d71f95" xmlns:ns2="ers.ise.cisco.com" xmlns:ns3="network.ers.ise.cisco.com">
  <link type="application/xml" href="https://hostname:9060/ers/config/networkdevice/123456" rel="self"/>
       <authenticationSettings>
          <enableKeyWrap>false</enableKeyWrap>
          <keyInputFormat>ASCII</keyInputFormat>
          <networkProtocol>RADIUS</networkProtocol>
          <radiusSharedSecret>******</radiusSharedSecret>
       </authenticationSettings>
       <NetworkDeviceIPList>
         <NetworkDeviceIP>
            <ipaddress>10.66.12.128</ipaddress>
            <mask>21</mask>
         </NetworkDeviceIP>
       </NetworkDeviceIPList>
       <NetworkDeviceGroupList>
         <NetworkDeviceGroup>Location#All Locations</NetworkDeviceGroup>
         <NetworkDeviceGroup>Device Type#All Device Types</NetworkDeviceGroup>
   </NetworkDeviceGroupList>
  </ns3:networkdevice>

有一个特殊之处:在file1中,我的标签称为: deviceName,ipAddress ,它们是 elements .
在file2中,我们有一个属性(因为它位于主元素 ns3:networkdevice 中,它被称为 name ,它从file1响应我们的deviceName),而另一个元素称为 ipaddress (文件1中的ipAddress)

There is smth special: In file1 my tags called: deviceName, ipAddress and they are elements.
In file2 we have one attribute (because it is staying in the main element ns3:networkdevice and it's called name what responds our deviceName from file1 ) and the other element is called ipaddress (ipAddress in file1)

推荐答案

您可以使用 XML :: Twig 解析两个响应.他们每个人都需要一个单独的解析器.

You can use XML::Twig to parse both responses. Each of them needs an individual parser.

对于第一个,您需要使用两个标签<deviceName><ipAddress>.对于访问 twig_handler 匹配元素的https://metacpan.org/pod/XML::Twig#text-@optional_options"rel =" nofollow noreferrer> text 属性就足够了.

For the first one, you need to go for the two tags <deviceName> and <ipAddress>. A simple twig_handler for each of them that access the text property of the matched element is sufficient.

那些处理程序可能很复杂,但是在我们的例子中,处理单个值的代码引用就足够了.我们知道每个值只有一次出现,因此我们可以将它们直接分配给它们各自的词法变量.

Those handlers can be complex, but in our case a code reference that deals with a single value is enough. We know that there is only one occurrence of each value, so we can directly assign both of them to their respective lexical variables.

use strict;
use warnings;
use XML::Twig;

my ($device_name, $ip_address);
XML::Twig->new(
    twig_handlers => {
        deviceName => sub { $device_name = $_->text },
        ipAddress => sub { $ip_address = $_->text },
    }
)->parse(\*DATA);

say $device_name;
say $ip_address;

__DATA__
<?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/201">
      <devicesDTO displayName="201201" id="201">
        <clearedAlarms>0</clearedAlarms>
        <collectionDetail></collectionDetail>
        <collectionTime></collectionTime>
        <creationTime></creationTime>
        <criticalAlarms>0</criticalAlarms>
        <deviceId>205571</deviceId>
        <deviceName>NEW-SW5</deviceName>
        <deviceType>Cisco Switch</deviceType>
        <informationAlarms>0</informationAlarms>
        <ipAddress>10.66.12.128</ipAddress>
      <location></location>
        <majorAlarms>0</majorAlarms>
        <managementStatus></managementStatus>
           <manufacturerPartNrs>
               <manufacturerPartNr></manufacturerPartNr>
           </manufacturerPartNrs>
           <minorAlarms>0</minorAlarms>
           <productFamily></productFamily>
           <reachability>Reachable</reachability>
           <softwareType>IOS</softwareType>
           <softwareVersion>12.1(22)</softwareVersion>
           <warningAlarms>0</warningAlarms>
      </devicesDTO>
   </entity>
</queryResponse>

对于第二个,您需要使用 att() 获取其中一个元素的 name 属性,但这也很简单.

For the second one you need to use att() to get the name attribute of one of the elements, but that's also straight-forward.

use strict;
use warnings;
use XML::Twig;

my ($device_name, $ip_address);
XML::Twig->new(
    twig_handlers => {
        'ns3:networkdevice' => sub { $device_name = $_->att('name') },
        ipaddress => sub { $ip_address = $_->text },
    }
)->parse(\*DATA);

say $device_name;
say $ip_address;
__DATA__
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<ns3:networkdevice name="NEW-SW5" id="9a6ef750-2620-11e4-81be-b83861d71f95" xmlns:ns2="ers.ise.cisco.com" xmlns:ns3="network.ers.ise.cisco.com">
<link type="application/xml" href="https://hostname:9060/ers/config/networkdevice/123456" rel="self"/>
     <authenticationSettings>
        <enableKeyWrap>false</enableKeyWrap>
        <keyInputFormat>ASCII</keyInputFormat>
        <networkProtocol>RADIUS</networkProtocol>
        <radiusSharedSecret>******</radiusSharedSecret>
     </authenticationSettings>
     <NetworkDeviceIPList>
       <NetworkDeviceIP>
          <ipaddress>10.66.12.128</ipaddress>
          <mask>21</mask>
       </NetworkDeviceIP>
     </NetworkDeviceIPList>
     <NetworkDeviceGroupList>
       <NetworkDeviceGroup>Location#All Locations</NetworkDeviceGroup>
       <NetworkDeviceGroup>Device Type#All Device Types</NetworkDeviceGroup>
 </NetworkDeviceGroupList>
</ns3:networkdevice>

现在,您同时拥有这两个功能,可以将它们组合在一起.我建议为每个函数创建一个函数,传递响应XML,并使它们返回$device_name$ip_address.

Now you that you have both of these, you can combine that. I suggest to create a function for each of them, pass in the response XML and make them return the $device_name and $ip_address.

use strict;
use warnings;
use XML::Twig;

sub parse_response_1 {
    my $xml = shift;

    my ( $device_name, $ip_address );
    XML::Twig->new(
        twig_handlers => {
            deviceName => sub { $device_name = $_->text },
            ipAddress  => sub { $ip_address  = $_->text },
        }
    )->parse($xml);

    return $device_name, $ip_address;
}

sub parse_response_2 {
    my $xml = shift;

    my ( $device_name, $ip_address );
    XML::Twig->new(
        twig_handlers => {
            'ns3:networkdevice' => sub { $device_name = $_->att('name') },
            ipaddress           => sub { $ip_address  = $_->text },
        }
    )->parse($xml);

    return $device_name, $ip_address;
}

当然,我的名字parse_response_1parse_response_2并不是最佳选择.不要使用数字,而应使用返回响应的服务的名称.

Of course my names parse_response_1 and parse_response_2 are not the best choice. Don't use the numbers, use the names of the services that returned the responses instead.

有了这两个功能,我们现在可以准确地检索所需的信息.剩下的就是检查它们.

With those two functions we now have the means to retrieve exactly the information that we want. All that's left is to check them.

sub check {
    my ( $response_1, $response_2 ) = @_;

    my ( $device_name_1, $ip_address_1 ) = parse_response_1($response_1);
    my ( $device_name_2, $ip_address_2 ) = parse_response_2($response_2);

    return $device_name_1 eq $device_name_2 && $ip_address_1 eq $ip_address_2;
}

再次,变量的名称可能会更好.现在,您只需要使用两个响应XML进行调用即可,它是否会返回真实值.

Again, the names of the variables could be better. Now you just need to call that with your two response XMLs and it will return a truthy value, or not.

这篇关于如何比较不同XML文档中的某些值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆