【问题标题】:Parsing xml files in perl在 perl 中解析 xml 文件
【发布时间】:2013-07-17 08:21:00
【问题描述】:

我需要存储xml数据

<pathway name="path:ko00010" org="ko" number="00010"
             title="Glycolysis / Gluconeogenesis"
             image="http://www.kegg.jp/kegg/pathway/ko/ko00010.png"
             link="http://www.kegg.jp/kegg-bin/show_pathway?ko00010">
        <entry id="13" name="ko:K01623 ko:K01624 ko:K01622 ko:K11645 ko:K16305 ko:K16306" type="ortholog" reaction="rn:R01070"
            link="http://www.kegg.jp/dbget-bin/www_bget?K01623+K01624+K01622+K11645+K16305+K16306">
            <graphics name="K01623..." fgcolor="#000000" bgcolor="#BFBFFF"
                 type="rectangle" x="483" y="404" width="46" height="17"/>
        </entry>
 </pathway>

放入数据结构中以供进一步使用。 DS 喜欢哈希和数组, 这是我的代码

#!/usr/bin/perl                                                                                                                                                                                                                                                                                                                                                             

use XML::LibXML;
use strict;
use warnings;
my $parser = new XML::LibXML;

my $xmlp= $parser -> parse_file("ko00010.xml");
my $rootel = $xmlp -> getDocumentElement();

my $elname = $rootel -> getName();
my @rootelements=$rootel -> getAttributes();


foreach my $rootatt(@rootelements){
    my  $name = $rootatt -> getName();
    my $value = $rootatt -> getValue();
    print " ${name}[$value]\n ";
}

my @kids = $rootel -> childNodes();
foreach my $child(@kids) {
    my $elname = $child -> getName();
    my @atts = $child -> getAttributes();
    foreach my $at (@atts) {
        my $name = $at -> getName();
        my $value = $at -> getValue();
        print " ${name}[$value]\n ";

    }
}

到目前为止,我可以访问除图形节点及其子节点之外的所有元素

【问题讨论】:

标签: xml perl


【解决方案1】:

另一种完全不同的方法:使用 XML 模式,并使用 CPAN 模块 XML::Compile 进行 XML 数据的自动转换。与 XML::Simple 等其他 xml-to-data 工具相比,XML::Compile 不必猜测或使用“ForceArray”等选项进行调整,如果子元素有时会变成数组,有时会变成一个标量。

如果您的数据没有 XML 架构,那么您可以使用 trang 自动创建一个:

trang testdata.xml schema.xsd

XML::Compile自带命令行工具xml2yaml快速转换:

xml2yaml testdata.xml schema.xsd > testdata.yaml

【讨论】:

  • 我真的不知道如何继续。在发布这个问题之前,我已经尝试了很多不同的模块,我更喜欢坚持使用这个 XML::lib
  • @shaq - 好吧,为了这个目的,你坚持使用错误的(即更难的)模块。 libxml 对某些东西有好处,但是对于返回你想要的数据结构,还有更合适的模块。
【解决方案2】:

我不清楚您要创建什么数据结构。或者当您可以使用 XPath 来获取您需要的数据而无需将 XML 映射到其他东西时为什么要创建数据结构。

在我看来,您有点想模仿 XML::Simple 所做的事情。在这种情况下,不直接使用 XML::Simple 吗?我知道一般不建议将它用于任何复杂的 XML,但如果您的 XML 很简单并且 XML::Simple 创建的数据适合您,那么使用广泛使用的模块可能比尝试重写它更安全(我应该知道,我用 XML::Twig 重写了它,不是特别难,但也不一定完全微不足道)。

【讨论】:

    【解决方案3】:

    你需要做的

    my @grand_kids = $child -> childNodes();
    

    在您的第二次 foreach 中并通过属性再执行一步

    我已经为你做了示例

    #!/usr/bin/perl     
    use XML::LibXML;
    use strict;
    use warnings;
    my $parser = new XML::LibXML;
    
    my $xmlp= $parser->parse_file("ko00010.xml");
    my $rootel = $xmlp->getDocumentElement();
    
    my $elname = $rootel->getName();
    my @rootelements=$rootel->getAttributes();
    
    foreach my $rootatt(@rootelements){
        printf "R {%s}[%s]\t", $rootatt->getName(), $rootatt->getValue();
    }
    
    my @kids = $rootel -> childNodes();
    foreach my $child(@kids) {
        printf "\nCH = %s\n",  $child->getName();
        my @atts = $child->getAttributes();
        foreach my $at (@atts) {
            printf "C {%s}[%s]\t", $at->getName(), $at->getValue();
        }
        my @grand_kids=$child->childNodes();
        foreach my $grand_child(@grand_kids) {
            printf "\nGR CH = %s\n",  $grand_child->getName();
            my @atts2 = $grand_child->getAttributes();
            foreach my $at2 (@atts2) {
                printf "GC {%s}[%s]\t", $at2->getName(), $at2->getValue();
            }
        }
    }
    

    给出这个输出 - (我不确定#text 节点来自哪里)

    R {name}[path:ko00010]  R {org}[ko] R {number}[00010]   R {title}[Glycolysis / Gluconeogenesis] R {image}[http://www.kegg.jp/kegg/pathway/ko/ko00010.png]   R {link}[http://www.kegg.jp/kegg-bin/show_pathway?ko00010]  
    CH = #text
    
    CH = entry
    C {id}[13]  C {name}[ko:K01623 ko:K01624 ko:K01622 ko:K11645 ko:K16305 ko:K16306]   C {type}[ortholog]  C {reaction}[rn:R01070] C {link}[http://www.kegg.jp/dbget-bin/www_bget?K01623+K01624+K01622+K11645+K16305+K16306]   
    GR CH = #text
    
    GR CH = graphics
    GC {name}[K01623...]    GC {fgcolor}[#000000]   GC {bgcolor}[#BFBFFF]   GC {type}[rectangle]    GC {x}[483] GC {y}[404] GC {width}[46]  GC {height}[17] 
    GR CH = #text
    
    CH = #text
    

    【讨论】:

    • 我试过这个,但在foreach my $child(@kids) Graphics 不是@kids 中的$child 之一。我的意思是childnodes() 不会将图形作为my @kids = $rootel -&gt; childNodes(); 中的节点返回
    • 感谢您的回答,尝试使用简单的xml,它确实很简单,我可以设法解析所有元素
    【解决方案4】:

    XML::Simple 可以,但也建议使用 LibXML。这是一个perlmonks article,关于一些显着差异以及从 XML::Simple 到 LibXML 的转换。

    使用 XPathContextfindnodes 使用 LibXML 的一种方法:

    use strict;
    use warnings;
    use XML::LibXML;
    use Data::Dumper;
    
    my $parser    = XML::LibXML->new();
    my $doc       = $parser->parse_file("ko00010.xml");
    my $root      = $doc->getDocumentElement();
    my %nodeHash  = ();
    
    # get list of nodes and stores each nodeName(key) and textContent(value) in %nodeHash
    my $perlmatch = sub {
        die "Not a nodelist"
          unless $_[0]->isa('XML::LibXML::NodeList');
        die "Missing a regular expression"
          unless defined $_[1];
        my $i = 0;
        while ( my $node = $_[0]->get_node($i++) ) {
            push @{ $nodeHash{$node->nodeName} }, $node->textContent; 
        }
    };
    
    # Create XPathContext and find all nodes
    my $xc = XML::LibXML::XPathContext->new($root);
    $xc->registerFunction( 'perlmatch', $perlmatch ); # register 'perlmatch' function   
    $xc->findnodes('perlmatch(//*, ".")') or die "Error retrieving nodes."; # //* is to go through all parent and child nodes, "." to match any nodeName
    
    print Dumper(%nodeHash); # print the contents of nodeHash (you can see the final hash structure here)
    

    取自CPAN XML::LibXML::XPath 上的示例(替换为哈希而不是数组,所有节点都使用“.”)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-28
      • 1970-01-01
      • 2012-03-27
      • 2013-04-16
      • 1970-01-01
      • 2011-08-08
      • 2011-03-25
      • 1970-01-01
      相关资源
      最近更新 更多