用Perl解析XML文档

用Perl解析XML文档,perl,xml-parsing,Perl,Xml Parsing,我有一个奇怪的XML文档,按照以下方式排列 <a> <b> <c c1="blah" c2="blah"> <d d1="blah0" d2="blah1" d3="blah2" d4="blah3" d5="blah4" /> <d d1="blah5" d2="blah6" d3="blah7" d4="blah8" d5="blah9" /> <d d1="bl

我有一个奇怪的XML文档,按照以下方式排列

<a>
   <b>
     <c c1="blah" c2="blah">
        <d d1="blah0" d2="blah1" d3="blah2" d4="blah3" d5="blah4" />
        <d d1="blah5" d2="blah6" d3="blah7" d4="blah8" d5="blah9" />
        <d d1="blah10" d2="blah11" d3="blah12" d4="blah13" d5="blah14" />
     </c>
     <c c1="blahc" c2="blah">
        <d d1="blah0" d2="blah1" d3="blah2" d4="blah3" d5="blah4" />
        <d d1="blah5" d2="blah6" d3="blah7" d4="blah8" d5="blah9" />
        <d d1="blah10" d2="blah11" d3="blah12" d4="blah13" d5="blah14" />
     </c>
    ...
  <b>
    ....
  </b>
  <e/>
</a>
,在数组引用方面遇到了很多困难。

我尝试使用,但考虑到我的XML文件大小为500MB,它似乎不是一个好的选择。请推荐一种好的方法,因为我是Perl新手。您的问题有点让人困惑,您想要的是
d
元素的属性,而不是
c
元素的属性。或者,无论
c
下的元素是什么,您都需要属性的值

在任何情况下,尤其是当文件很大时,这看起来很适合:

#/usr/bin/perl
严格使用;
使用警告;
使用XML::Twig;
XML::Twig->new(Twig\u处理程序=>{'b/c/*'=>\&get\u atts})
->解析(\*数据);#替换为parsefile('my.xml')
分包合同
{my($t,$elt)=@;
每个我的$att(qw(d2 d4 d5))
{打印“$att:”,$elt->att($att),”;}
打印“\n”;
$t->purge;#这将释放内存,因此最多保留1个d元素
}
__资料__

如果属性总是在
d
元素中,请将
'b/c/*'
替换为
'b/c/d'
,这样效率会更高。

您的问题有点混乱,您想要
d
元素的属性,而不是
c
元素的属性。或者,无论
c
下的元素是什么,您都需要属性的值

在任何情况下,尤其是当文件很大时,这看起来很适合:

#/usr/bin/perl
严格使用;
使用警告;
使用XML::Twig;
XML::Twig->new(Twig\u处理程序=>{'b/c/*'=>\&get\u atts})
->解析(\*数据);#替换为parsefile('my.xml')
分包合同
{my($t,$elt)=@;
每个我的$att(qw(d2 d4 d5))
{打印“$att:”,$elt->att($att),”;}
打印“\n”;
$t->purge;#这将释放内存,因此最多保留1个d元素
}
__资料__
如果属性始终位于
d
元素中,请将
'b/c/*'
替换为
'b/c/d'
,这样效率更高。

使用:

更新:(对于mirod):使用来自Perl的XML::XSH2不那么优雅,但仍然可以工作-

#!/usr/bin/perl
use strict;
use warnings;

use XML::XSH2;

xsh q{
    open 1.xml ;
    for /a/b/c/d {
        for my $attr in (@d2 | @d4 | @d5) {
            perl { push @ar, $attr }
        }
    }
};

printf "%s:%s\n", $_->name, $_->value for @XML::XSH2::Map::ar;
或者,让Perl为您编写xsh代码:

#!/usr/bin/perl
use warnings;
use strict;

use XML::XSH2;

xsh 'open 1.xml';
xsh '$attributes = (' . join('|', map 'a/b/c/@d' . $_, 1, 2, 4) . ')';
for (@$XML::XSH2::Map::attributes) {
    print $_->name, '=', $_->value, "\n";
}
使用:

更新:(对于mirod):使用来自Perl的XML::XSH2不那么优雅,但仍然可以工作-

#!/usr/bin/perl
use strict;
use warnings;

use XML::XSH2;

xsh q{
    open 1.xml ;
    for /a/b/c/d {
        for my $attr in (@d2 | @d4 | @d5) {
            perl { push @ar, $attr }
        }
    }
};

printf "%s:%s\n", $_->name, $_->value for @XML::XSH2::Map::ar;
或者,让Perl为您编写xsh代码:

#!/usr/bin/perl
use warnings;
use strict;

use XML::XSH2;

xsh 'open 1.xml';
xsh '$attributes = (' . join('|', map 'a/b/c/@d' . $_, 1, 2, 4) . ')';
for (@$XML::XSH2::Map::attributes) {
    print $_->name, '=', $_->value, "\n";
}

CPAN中有许多XML模块可以帮助您实现这一点,但在本例中,我的重点是,它允许您简洁地描述要从XML中提取的数据

此程序使用示例数据并提供我认为您需要的输出(尽管严格来说,任何
节点都没有
d=“xx”
属性)

使用严格;
使用警告;
使用特征“说”;
使用XML::XPath;
我的$xml=xml::XPath->new(ioref=>\*数据);
对于我的$cnode($xml->find('//b/c/d')->get\u nodelist){
对于($cnode->find('@d2 |@d4 |@d5')->get_nodelist){
打印$->getData,“\n”;
}
}
__资料__
...
输出

blah1
废话
废话
废话
废话
废话
废话11
废话13
废话14
胡说八道
废话
废话
废话
废话
废话
废话11
废话13
废话14

CPAN中有许多XML模块可以帮助您实现这一点,但在本例中,我的钱就在上面,它允许您简洁地描述要从XML中提取的数据

此程序使用示例数据并提供我认为您需要的输出(尽管严格来说,任何
节点都没有
d=“xx”
属性)

使用严格;
使用警告;
使用特征“说”;
使用XML::XPath;
我的$xml=xml::XPath->new(ioref=>\*数据);
对于我的$cnode($xml->find('//b/c/d')->get\u nodelist){
对于($cnode->find('@d2 |@d4 |@d5')->get_nodelist){
打印$->getData,“\n”;
}
}
__资料__
...
输出

blah1
废话
废话
废话
废话
废话
废话11
废话13
废话14
胡说八道
废话
废话
废话
废话
废话
废话11
废话13
废话14

能否更具体地说明XML::Simple的问题?在某些XML文件中,“b”节点为空,这意味着每次处理此类XML文件时都会出现数组引用错误。您可以在尝试访问它之前添加条件;执行if(defined{path to node}){do which}500MB对于当前机器来说不是很多内存中的数据,因此XML::DOM将是一个有效的选择。主要的选择实际上取决于您是喜欢
DOM
还是
XPath
,还是喜欢XML::Twig等非标准的东西。顺便问一下,“请推荐一个好的方法,因为我是Perl新手”,您是在建议我们应该为有经验的Perl程序员保留我们糟糕的建议吗?!您能否更具体地说明XML::Simple的问题?在某些XML文件中,“b”节点为空,这意味着每次处理此类XML文件时都会出现数组引用错误。您可以在尝试访问它之前添加一个条件;执行if(defined{path to node}){do which}500MB对于当前机器来说不是很多内存中的数据,因此XML::DOM将是一个有效的选择。主要的选择实际上取决于您是喜欢
DOM
还是
XPath
,还是喜欢XML::Twig等非标准的东西。顺便问一下,“请推荐一个好的方法,因为我是Perl新手”,您是在建议我们应该为有经验的Perl程序员保留我们糟糕的建议吗?!我经常看到你的答案使用xsh。它们通常非常优雅。但是,从代码中使用xsh有多容易?通常情况下,目标不仅仅是打印结果,而是做一些工作