【问题标题】:iterating through elements using libxml in perl在 perl 中使用 libxml 遍历元素
【发布时间】:2017-10-24 19:33:24
【问题描述】:

我有一个如下所示的 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";
    }
}

【问题讨论】:

    标签: xml perl xpath xml-libxml


    【解决方案1】:

    使用XML::LibXML::Node提供的nonBlankChildNodesnodeNametextContent方法:

    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-2.0126,但它似乎不支持 Node.js。不确定我是否想参与安装较新版本。有其他选择吗?
    • 这是XML::LibXML 的一个相当新的版本,我相当肯定你会拥有XML::LibXML::Node。命令行中的perl -MXML::LibXML::Node -e 1 返回什么?
    • 返回找不到“Can't locate XML/LibXML/Node.pm in @INC (@INC contains: /app/ac/local/lib/perl5 /app)”的错误/ac/lib/perl5 /app/localapps/perl/lib/sun4-solaris-64int"
    • 您是否收到与perl -MXML::LibXML -e 1 相同的消息?
    • Re "我用的是XML-LibXML-2.0126,好像不支持Node.",根本不是这样。所有版本的 XML::LibXML 都有 ::Node。它是每个 DOM 对象的基类。 (XML::LibXML::Node 没有自己的文件,这就是 use XML::LibXML::Node; 和类似文件失败的原因。它由 use XML::LibXML; 提供。)
    【解决方案2】:

    你确定要这个吗?从解析的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,
            },
        },
    }
    

    【讨论】:

      猜你喜欢
      • 2014-07-03
      • 1970-01-01
      • 2014-03-24
      • 2011-08-19
      • 2020-08-05
      • 2012-07-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多