Перебирая элементы используя libxml в perl
У меня есть файл XML, как показано ниже,
<?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";
}
}
2 ответа
Использовать nonBlankChildNodes
, nodeName
а также textContent
методы, предоставляемые XML::LibXML::Node
:
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;
Вы уверены, что хотите этого? Так же просто получить доступ к произвольным данным из проанализированного 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,
},
},
}