итерация през елементи с помощта на libxml в perl

I have an XML file like below,

<?xml version="1.0"?>
<data>
  <header>
    <name>V9 Red Indices</name>
    <version>9</version>
    <date>2017-03-16</date>
  </header>
  <index>
    <indexfamily>ITRAXX-Asian</indexfamily>
    <indexsubfamily>iTraxx Rest of Asia</indexsubfamily>                
    <paymentfrequency>3M</paymentfrequency>
    <recoveryrate>0.35</recoveryrate>
    <constituents>
      <constituent>
        <refentity>
          <originalconstituent>
            <referenceentity>ICICI Bank Limited</referenceentity>
            <redentitycode>Y1BDCC</redentitycode>
            <role>Issuer</role>
            <redpaircode>Y1BDCCAA9</redpaircode>
            <jurisdiction>India</jurisdiction>
            <tier>SNRFOR</tier>
            <pairiscurrent>false</pairiscurrent>
            <pairvalidfrom>2002-03-30</pairvalidfrom>
            <pairvalidto>2008-10-22</pairvalidto>
            <ticker>ICICIB</ticker>
            <ispreferred>false</ispreferred>
            <docclause>CR</docclause>
            <recorddate>2014-02-25</recorddate>
            <weight>0.0769</weight>
          </originalconstituent>
        </refentity>
        <refobligation>
          <type>Bond</type>
          <isconvert>false</isconvert>
          <isperp>false</isperp>
          <coupontype>Fixed</coupontype>
          <ccy>USD</ccy>
          <maturity>2008-10-22</maturity>
          <coupon>0.0475</coupon>
          <isin>XS0178885876</isin>
          <cusip>Y38575AQ2</cusip>
          <event>Matured</event>
          <obligationname>ICICIB 4.75 22Oct08</obligationname>
          <prospectusinfo>
            <issuers>                                                        
              <origissuersasperprosp>ICICI Bank Limited</origissuersasperprosp>
            </issuers>
          </prospectusinfo>
        </refobligation>
      </constituent>
    </constituents>
  </index>
</data>

Бих искал да прегледам този файл, без да знам имената на таговете. Крайната ми цел е да създам хеш с имена и стойности на тагове.

Не искам да използвам findnodes с XPath за всеки възел. Това проваля цялата цел на писането на общ зареждащ механизъм.

Също така използвам XML-LibXML-2.0126, малко по-стара версия.

Част от моя код, който използва findnodes, е по-долу. XML също беше съкратен, за да се избегне дълга заявка, в която се превърна сега :)

use XML::LibXML;

my $xmldoc = $parser->parse_file( $fileName );
my $root = $xmldoc->getDocumentElement() || die( "Could not get Document Element \n" );

foreach my $index ( $root->findnodes( "index" ) ) {    # $root->getChildNodes()) # Get all the Indexes

    foreach my $constituent ( $index->findnodes( 'constituents/constituent' ) ) { # Lets pick up all Constituents

        my $referenceentity = $constituent->findnodes( 'refentity/originalconstituent/referenceentity' );    # This is a crude way. we should be iterating without knowing whats inside

        print "referenceentity :" . $referenceentity . "\n";
        print "+++++++++++++++++++++++++++++++++++ \n";
    }
}

person BRATVADDI    schedule 24.05.2017    source източник


Отговори (2)


Използвайте методите nonBlankChildNodes, nodeName и textContent, предоставени от XML::LibXML::Node< /a>:

my %hash;

for my $node ( $oc->nonBlankChildNodes ) {

    my $tag = $node->nodeName;
    my $value = $node->textContent;
    $hash{$tag} = $value;
}

Което е еквивалентно на:

my %hash = map { $_->nodeName, $_->textContent } $oc->nonBlankChildNodes;
person Zaid    schedule 24.05.2017
comment
Изглежда добре.. Въпреки че използвам XML-LibXML-2.0126 и това изглежда не поддържа Node. Не съм сигурен дали искам да се включа в инсталирането на по-новата версия. има ли алтернатива - person BRATVADDI; 24.05.2017
comment
Това е сравнително нова версия на XML::LibXML, почти съм сигурен, че ще имате XML::LibXML::Node. Какво връща perl -MXML::LibXML::Node -e 1 на командния ред? - person Zaid; 24.05.2017
comment
връща грешката, че не може да намери Не мога да намеря XML/LibXML/Node.pm в @INC (@INC съдържа: /app/ac/local/lib/perl5 /app/ac/lib/perl5 /app/ localapps/perl/lib/sun4-solaris-64int - person BRATVADDI; 24.05.2017
comment
Получавате ли същото съобщение с perl -MXML::LibXML -e 1? - person Zaid; 24.05.2017
comment
Не, изглежда, че работи добре. не дава никакви грешки.. perl -MXML::LibXML::NodeLis -e 1 ; изглежда също добре.. може да е бъгова инсталация? - person BRATVADDI; 24.05.2017
comment
Ха, в такъв случай дори findnodes няма да работи, тъй като се предоставя от същия пакет. Не виждам как би било възможно да обходя документа без XML::LibXML::Node - person Zaid; 24.05.2017
comment
findnodes всъщност работи :) Използвам го от известно време. Не исках да напиша findnodes за всеки отделен елемент и оттам този въпрос. - person BRATVADDI; 24.05.2017
comment
Мисля, че ще трябва да видим как ще го използвате, за да разберете какво се случва тук тогава. Може да се инсталира в отделен път, който не е част от @INC, може би? - person Zaid; 24.05.2017
comment
Re Използвам XML-LibXML-2.0126 и изглежда, че не поддържа Node., това изобщо не е така. Всички версии на XML::LibXML имат ::Node. Това е базовият клас на всеки DOM обект. (XML::LibXML::Node няма собствен файл, поради което use XML::LibXML::Node; и подобни се провалят. Предоставя се от use XML::LibXML;.) - person ikegami; 24.05.2017
comment
Объркването беше опитът да се намери XML::LibXML::Node. Решението работи добре. Благодаря! - person BRATVADDI; 26.05.2017

Сигурни ли сте, че искате това? Също толкова лесно е да получите достъп до произволни данни от анализиран XML::LibXML::Document обект, както и от вложен Perl хеш. Със сигурност ще заема по-малко място в паметта от еквивалентния обект, ако това е вашето намерение, но от въпроса ви не изглежда така

Можете да направите това лесно с помощта на модула XML::Parser, който извиква обратно извикване при всяко „събитие " се среща в XML данните. В този случай всичко, което ни интересува, е отворен таг, затворен таг и текстов низ

Този примерен код изгражда вложен хеш от XML. Той умира с подходящо съобщение, ако XML данните са неправилно формирани (затварящ таг не съвпада с името на отварящ таг) или ако някой от елементите има един или повече атрибути, които не могат да бъдат представени в тази структура

Използвах Data::Dump за показване на резултата

use strict;
use warnings 'all';

use XML::Parser;
use Data::Dump;

my $parser = XML::Parser->new(
    Style    => 'Debug',
    Handlers => {
        Start => \&handle_start,
        End   => \&handle_end,
        Char  => \&handle_char,
    },
);


my %data;
my @data_stack = ( \%data );
my @elem_stack;

$parser->parsefile( 'index.xml' );
dd \%data;


sub handle_start {
    my ($expat, $elem) = @_;

    my $data = $data_stack[-1]{$elem} = { };
    push @data_stack, $data;
    push @elem_stack, $elem;

    if ( @_ > 2 ) {
        my $xpath = join '', map "/$_", @elem_stack;
        die qq{Element at $xpath has attributes};
    }
}


sub handle_end {
    my ($expat, $elem) = @_;

    my $top_elem = pop @elem_stack;
    die qq{Bad XML structure $elem <=> $top_elem} unless $elem eq $top_elem;

    pop @data_stack;
}


sub handle_char {
    my ($expat, $str) = @_;

    return unless $str =~ /\S/;

    my $top_elem = $elem_stack[-1];

    $data_stack[-2]{$top_elem} = $str;
}

изход

{
    data => {
        header => {
            date => "2017-03-16",
            name => "V9 Red Indices",
            version => 9,
        },
        index  => {
            constituents => {
                constituent => {
                    refentity => {
                        originalconstituent => {
                            docclause       => "CR",
                            ispreferred     => "false",
                            jurisdiction    => "India",
                            pairiscurrent   => "false",
                            pairvalidfrom   => "2002-03-30",
                            pairvalidto     => "2008-10-22",
                            recorddate      => "2014-02-25",
                            redentitycode   => "Y1BDCC",
                            redpaircode     => "Y1BDCCAA9",
                            referenceentity => "ICICI Bank Limited",
                            role            => "Issuer",
                            ticker          => "ICICIB",
                            tier            => "SNRFOR",
                            weight          => 0.0769,
                        },
                    },
                    refobligation => {
                        ccy            => "USD",
                        coupon         => 0.0475,
                        coupontype     => "Fixed",
                        cusip          => "Y38575AQ2",
                        event          => "Matured",
                        isconvert      => "false",
                        isin           => "XS0178885876",
                        isperp         => "false",
                        maturity       => "2008-10-22",
                        obligationname => "ICICIB 4.75 22Oct08",
                        prospectusinfo => {
                            issuers => {
                                origissuersasperprosp => "ICICI Bank Limited"
                            },
                        },
                        type => "Bond",
                    },
                },
            },
            indexfamily      => "ITRAXX-Asian",
            indexsubfamily   => "iTraxx Rest of Asia",
            paymentfrequency => "3M",
            recoveryrate     => 0.35,
        },
    },
}
person Borodin    schedule 24.05.2017