मैं अलग-अलग XML दस्तावेज़ों से कुछ मानों की तुलना कैसे करूं?




perl xml-parsing (4)

पहले ध्यान दें कि दो एक्सएमएल फाइलों के लिए "समान" होने के लिए इसका कोई सार्वभौमिक समझौता नहीं है। उदाहरण के लिए, हर कोई इस बात से सहमत है कि शुरुआत और समाप्ति टैग के भीतर श्वेत स्थान को अनदेखा करना चाहिए, और यह कि गुणों के बीच एकल और दोहरे उद्धरण चिह्नों के बीच का अंतर अप्रासंगिक है, और ये गुण किसी भी क्रम में हो सकते हैं; लेकिन आवश्यकताएं टिप्पणियों, तत्व टैग, नाम स्थान उपसर्गों और कई अन्य विवरणों के बीच सफेद स्थान को कैसे प्रबंधित करें, इसके बारे में भिन्नता है।

एक अन्य क्षेत्र जहां आवश्यकताएं अलग-अलग हैं, वह जानकारी है जिसे आप चाहते हैं कि जब दस्तावेज़ अलग-अलग समझा जाए कुछ तंत्र केवल आपको एक हाँ-या-कोई जवाब देंगे, और मतभेदों को खोजने में आपकी मदद नहीं करेगा

इसका नतीजा यह है कि वहाँ सामान्य प्रयोजन समाधान हो सकते हैं, लेकिन वे हमेशा आपकी विशिष्ट आवश्यकताओं को पूरा नहीं कर सकते हैं।

तो अपने खुद के तुलनित्र लेखन एक हास्यास्पद विचार नहीं है अगर आप कोड के कुछ सौ लाइन लिखने के लिए तैयार हैं

लेकिन दो ऑफ-शेल्फ समाधान जो आप सोच सकते हैं, यदि आप उदाहरण पार्ल पर्यावरण में चला सकते हैं, तो ये हैं:

  • एक्सएमएल केनोनाइलाइज़रः दोनों दस्तावेजों को कैनोनिकल बना सकते हैं और फिर बाइनरी स्तर पर परिणामों की तुलना करें।

  • XPath 2.0: दो नोड्स (दस्तावेज़ नोड्स सहित) की तुलना करने के लिए गहरा-समान () फ़ंक्शन प्रदान करता है

मैं पर्ल में कोड लिखना चाहता हूँ जो दो एक्सएमएल फाइलों की तुलना करता है।

इतिहास से थोड़ा सा ... एपीआई दस्तावेज़ीकरण (अनुरोध प्राप्त करें) के साथ मुझे डेटा 1 फॉर्म 1 से वेब सर्विस 1 और डेटा 2 मिलता है। वे एक्सएमएल प्रारूप में प्रस्तुत किए जाते हैं, लेकिन वही नहीं।

मुझे इन फ़ाइलों (डिवाइस नाम और ipAddress) में सिर्फ दो तत्वों की तुलना करनी चाहिए, यदि वे दोनों फाइल में समान हैं, तो यह "WebService1 पहले से ही DeviceName" स्विच 1 "" संदेश होना चाहिए। यदि नहीं - मैं पोस्ट अनुरोध करना चाहूंगा और इस उपकरण को WebService1 / WebService2 में जोड़ूँगा

क्या आप मुझे सलाह दे सकते हैं, मुझे किस मॉड्यूल का उपयोग करना चाहिए और इस तुलना से मुझे कैसे शुरू करना चाहिए?

उदाहरण के लिए (फ़ाइल 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>

करें 2

  <?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>

वहाँ विशेष smth है : file1 मेरे टैग बुलाया: deviceName, ipAddress और वे तत्व हैं
File2 में हमारे पास एक विशेषता है (क्योंकि यह मुख्य तत्व ns3: networkdevice में रह रहा है और इसे नाम दिया गया है जो file1 से हमारे डिवाइस का नाम देता है) और अन्य तत्व को आईपैड्रेस कहा जाता है (फ़ाइल 1 में आईपीएड्रेस)


प्रतिक्रियाओं को पार्स करने के लिए आप XML :: ट्वीग का उपयोग कर सकते हैं। उनमें से प्रत्येक को एक व्यक्तिगत पार्सर की जरूरत है

पहले के लिए, आपको दो टैग <deviceName> और <ipAddress> । उनमें से प्रत्येक के लिए एक सरल twig_handler जो मिलान किए गए तत्व की text प्रॉपर्टी तक पहुंचने में पर्याप्त है।

ये हैंडलर जटिल हो सकते हैं, लेकिन हमारे मामले में एक कोड संदर्भ जो एक मूल्य के साथ सौदे करता है पर्याप्त है। हम जानते हैं कि प्रत्येक मूल्य की केवल एक ही घटना है, इसलिए हम दोनों को सीधे उनके संबंधित लेक्सिकल वेरिएबल्स में निर्दिष्ट कर सकते हैं।

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() का उपयोग करने की आवश्यकता है, लेकिन यह भी सीधे आगे है

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 लौटाता हूं।

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_1 और parse_response_2 सबसे अच्छा विकल्प नहीं हैं parse_response_2 संख्याओं का उपयोग न करें, उन सेवाओं के नामों का उपयोग करें, जो जवाबों को लौटते हैं।

उन दोनों फ़ंक्शंस के साथ हमारे पास अभी वह जानकारी प्राप्त करने का मतलब है जो हम चाहते हैं। उन सभी को छोड़ना है जो उन्हें जांचना है।

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 के साथ कॉल करने की ज़रूरत है और यह एक सच्ची मूल्य वापस करेगा या नहीं।


यह खरोंच से लिखना एक सरल काम नहीं है। आपको XML::Compare उपयोग करना चाहिए XML::Compare


use XML::Simple;
use Data::Dumper;

my $file1_ref = XMLin("./file1");
my $file2_ref = XMLin("./file2");

if($file2_ref->{NetworkDeviceIPList}->{NetworkDeviceIP}->{ipaddress} eq $file1_ref->{entity}->{devicesDTO}->{ipAddress} && $file2_ref->{name} eq $file1_ref->{entity}->{devicesDTO}->{deviceName}) {
  print "WebService1 already contains DeviceName \"".$file2_ref->{name}."\"\n";
} else {
  # POST request and add this device in WebService1/WebService2
  # Code here ....                                                                                                                                                                                                                                                              
}

आप कॉल को तरीकों में बदल सकते हैं और मैं दृढ़ता से सुझाव देता हूं कि आप रूपांतरण के आसपास जोड़ और ईलाइंस करते हैं और त्रुटियों की जांच करते हैं, अगर वापस लौट XML बगली हो





perl-module