简体   繁体   中英

Perl - Sorting an array of XML query data

I'm a newbie in Perl and I'm trying to sort an array of XML elements from 6 similar XMLs. The code below has 2 of the 6 files as recommended. I've tried the sort function with substrings but it hasn't worked yet. Can anyone check and help me make it work?

use 5.010;
use warnings;
use XML::LibXML;
use XML::XPath;
use XML::XPath::XMLParser;

my $dom1 = XML::XPath->new(filename => './xml/nota1.xml');
my $dom2 = XML::XPath->new(filename => './xml/nota5.xml');

my @list;

foreach my $vProd ($dom1->find('//prod'), $dom2->find('//prod')){
      push @list, $vProd;
}
say @list;

All XML files have a "prod" element that contains information about products, and I want to sort by an element called "vProd". "vProd" is the ninth element and it's the product's value in my country's currency. Below are both XML files:

nota1.xml

<?xml version="1.0" encoding="UTF-8"?>
<list>
    <prod>
        <cProd>025-1220-318-40</cProd>
        <cEAN>4051411545402</cEAN>
        <xProd>Chuteira Puma Esito Finale IT</xProd>
        <NCM>64029990</NCM>
        <CFOP>6108</CFOP>
        <uCom>PAR</uCom>
        <qCom>1</qCom>
        <vUnCom>94.91</vUnCom>
        <vProd>94.91</vProd>
        <cEANTrib>4051411545402</cEANTrib>
        <uTrib>PAR</uTrib>
        <qTrib>1</qTrib>
        <vUnTrib>94.91</vUnTrib>
        <indTot>1</indTot>
    </prod>
</list>

nota5.xml

<?xml version="1.0" encoding="UTF-8"?>
<list>
    <prod>
        <cProd>AEMC815BZA</cProd>
        <cEAN>0885909455232</cEAN>
        <xProd>MAC MINI COREI5 2GB500GB | 0885909455232| Rua: A</xProd>
        <NCM>84715010</NCM>
        <CFOP>5929</CFOP>
        <uCom>PC</uCom>
        <qCom>1.0000</qCom>
        <vUnCom>1606.0000</vUnCom>
        <vProd>1606.00</vProd>
        <cEANTrib>0885909455232</cEANTrib>
        <uTrib>PC</uTrib>
        <qTrib>1.0000</qTrib>
        <vUnTrib>1606.0000</vUnTrib>
        <indTot>1</indTot>
    </prod>
    <prod>
        <cProd>AEMD032BZA</cProd>
        <cEAN>0885909480920</cEAN>
        <xProd>ROTEADOR TIME CAPSULE 2TB BCO | 0885909480920| Rua: A</xProd>
        <NCM>84717019</NCM>
        <CFOP>5929</CFOP>
        <uCom>PC</uCom>
        <qCom>1.0000</qCom>
        <vUnCom>852.0000</vUnCom>
        <vProd>852.00</vProd>
        <cEANTrib>0885909480920</cEANTrib>
        <uTrib>PC</uTrib>
        <qTrib>1.0000</qTrib>
        <vUnTrib>852.0000</vUnTrib>
        <indTot>1</indTot>
    </prod>
</list>

Thanks in advance!

First, let's construct our list of prod elements:

use XML::LibXML;

my @qfns = ( 'xml/nota1.xml', 'xml/nota5.xml', ... );

my @prod_eles;
for my $qfn (@qfns) {
    my $doc = XML::LibXML->load_xml( location => $qfn );
    push @prod_eles, $doc->findnodes('/list/prod');
}

I used XML::LibXML because I'm familiar with it, it's very fast, it's very reliable, and because you are loading it (even if you aren't using it).

Now, we just have to sort the elements. There's nothing particularly special about your case. Using XPath, we can easily query the objects for the values we want to compare.

@prod_eles =
   sort { $a->findvalue('vProd') <=> $b->findvalue('vProd') }
      @prod_eles;

To speed things up, we could also use the following instead:

use Sort::Key qw( nkeysort );

@prod_eles =
   nkeysort { $_->findvalue('vProd') }
      @prod_eles;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM