如何使用 Perl 的 XML::Twig 在 XML 中显示后代?
How to display descendants in XML with Perl's XML::Twig?
我是 2 周大的 Perl 用户,我正在尝试解析一个 300 MB 的嵌套 XML 文件。所以请原谅我缺乏知识。该文件遵循与下面类似的格式
<?xml version="1.0" encoding="UTF-8"?>
<APP:Report xsi:schemaLocation="WWW" xmlns:xsi="WWW" xmlns:APP="WWW">
<library>
<elt>
<Book>The book of pages</Book>
<Snap></Snap>
<Line1>The Beginning</Line1>
<Line2>We ceased to exist</Line2>
<Line3>Accept it</Line3>
<Line4>Now we live</Line4>
<Line5>We reject it</Line5>
<Rating>
<C1>6.1</C1>
<C2>8.9</C2>
<C3>9.4</C3>
</Rating>
</elt>
<Author>Sally</Author>
<Publisher>Penguin</Publisher>
<elt>
<Book>The song</Book>
<Snap></Snap>
<Line1>This is how we do it</Line1>
<Line2>I hope this works</Line2>
<Line3>Please do</Line3>
<Line4>Begging you</Line4>
<Line5>Bye</Line5>
<Rating>
<C1>2.3</C1>
<C2>9.9</C2>
<C3>4.5</C3>
</Rating>
</elt>
<Author>Justin</Author>
<Publisher>Victoria</Publisher>
</library>
</APP:Report>
我希望能够在第一行的不同列中显示 Book、Snap、Line1、Line2、line3、Line4、line5、C1、C2 和 C3,在第 2 行显示 Author,在第 3 行显示 Publisher . 这只是我拥有的大文件的一个示例。我不想访问要显示的特定子项。我希望能够显示它的所有后代。
目前它正在打印我所有的数据行 1 列 1。我的代码片段附在下面。最好的方法是什么?我将不胜感激任何建议。谢谢!
my $twig= new XML::Twig();
$twig->parsefile( $_); # build the twig
foreach my $elt ($twig->root->children)
{
print $fout1 $elt->text."\n";
}
编辑问题:如果我在嵌套子项中嵌套子项怎么办?什么是最有效的呢?例如,如何访问每个 C 的 elt 元素?我的第二个问题是关于如何显示这些元素,例如
The book of pages|Snap|Line1|Line2|Line3|Line4|Line5|C1.X|
The book of pages|Snap|Line1|Line2|Line3|Line4|Line5|C1.Y|
The book of pages|Snap|Line1|Line2|Line3|Line4|Line5|C2.X|
The book of pages|Snap|Line1|Line2|Line3|Line4|Line5|C2.Y|
The book of pages|Snap|Line1|Line2|Line3|Line4|Line5|C3.X|
The book of pages|Snap|Line1|Line2|Line3|Line4|Line5|C3.Y|
.
.
.
.
.
The song|Snap|Line1|Line2|Line3|Line4|Line5|C2.X|
The song|Snap|Line1|Line2|Line3|Line4|Line5|C2.Y|
Example
<Rating>
<C1>
<elt>
<X></X>
<X></X>
</elt>
<elt>
<elt>
</C1>
<C2>
<elt>
<elt>
<elt>
</C2>
<C3>
<elt>
<elt>
<elt>
</C3>
</Rating>
正如 ikegami 所建议的,最简单的方法是创建一个评级处理程序。但问题是解析它所花费的时间。我要解析的文件是 300 mb,有大约 20 个这样的例程,比如评级。所以我把大套路解析一次,然后把大套路的一部分解析20次。还有另一种方法吗?是否有另一个 XML 模块比 XML::Twig 更有用?
因此您希望节点匹配 XPath
descendant:*[count(*)=0]
又名
.//*[count(*)=0]
相对于 elt
元素。我用XML::LibXML,所以我会
$elt_node->findnodes("descendant:*[count(*)=0]")
XML::Twig 应该可以提供类似的解决方案。 (确实有 findnodes
。)
ug,我忘了 XML::Twig 对 XPath 的支持有多糟糕。它不知道 count
,并且 *
匹配非元素。没问题,我们只需要自己完成工作即可。
use strict;
use warnings;
use feature qw( say );
use XML::Twig qw( );
my @eles = qw( Book Snap Line1 Line2 Line3 Line4 Line5 C1 C2 C3 );
my $twig = XML::Twig->new(
twig_handlers => {
'/APP:Report/library/elt' => sub {
my ($twig, $ele) = @_;
my %row =
map { $_->name() => $_->text() // '' }
# $ele->findnodes("descendant:*[count(*)=0]")
grep { $_->name() ne '#PCDATA' && ( grep { $_->name() ne '#PCDATA' } $_->children ) == 0 }
$ele->descendants();
say join '|', @row{@eles};
$twig->purge(); # Free unneeded memory.
},
},
);
say join '|', @eles;
$twig->parsefile('my_big.xml');
输出:
Book|Snap|Line1|Line2|Line3|Line4|Line5|C1|C2|C3
The book of pages||The Beginning|We ceased to exist|Accept it|Now we live|We reject it|6.1|8.9|9.4
The song||This is how we do it|I hope this works|Please do|Begging you|Bye|2.3|9.9|4.5
我是 2 周大的 Perl 用户,我正在尝试解析一个 300 MB 的嵌套 XML 文件。所以请原谅我缺乏知识。该文件遵循与下面类似的格式
<?xml version="1.0" encoding="UTF-8"?>
<APP:Report xsi:schemaLocation="WWW" xmlns:xsi="WWW" xmlns:APP="WWW">
<library>
<elt>
<Book>The book of pages</Book>
<Snap></Snap>
<Line1>The Beginning</Line1>
<Line2>We ceased to exist</Line2>
<Line3>Accept it</Line3>
<Line4>Now we live</Line4>
<Line5>We reject it</Line5>
<Rating>
<C1>6.1</C1>
<C2>8.9</C2>
<C3>9.4</C3>
</Rating>
</elt>
<Author>Sally</Author>
<Publisher>Penguin</Publisher>
<elt>
<Book>The song</Book>
<Snap></Snap>
<Line1>This is how we do it</Line1>
<Line2>I hope this works</Line2>
<Line3>Please do</Line3>
<Line4>Begging you</Line4>
<Line5>Bye</Line5>
<Rating>
<C1>2.3</C1>
<C2>9.9</C2>
<C3>4.5</C3>
</Rating>
</elt>
<Author>Justin</Author>
<Publisher>Victoria</Publisher>
</library>
</APP:Report>
我希望能够在第一行的不同列中显示 Book、Snap、Line1、Line2、line3、Line4、line5、C1、C2 和 C3,在第 2 行显示 Author,在第 3 行显示 Publisher . 这只是我拥有的大文件的一个示例。我不想访问要显示的特定子项。我希望能够显示它的所有后代。
目前它正在打印我所有的数据行 1 列 1。我的代码片段附在下面。最好的方法是什么?我将不胜感激任何建议。谢谢!
my $twig= new XML::Twig();
$twig->parsefile( $_); # build the twig
foreach my $elt ($twig->root->children)
{
print $fout1 $elt->text."\n";
}
编辑问题:如果我在嵌套子项中嵌套子项怎么办?什么是最有效的呢?例如,如何访问每个 C 的 elt 元素?我的第二个问题是关于如何显示这些元素,例如
The book of pages|Snap|Line1|Line2|Line3|Line4|Line5|C1.X|
The book of pages|Snap|Line1|Line2|Line3|Line4|Line5|C1.Y|
The book of pages|Snap|Line1|Line2|Line3|Line4|Line5|C2.X|
The book of pages|Snap|Line1|Line2|Line3|Line4|Line5|C2.Y|
The book of pages|Snap|Line1|Line2|Line3|Line4|Line5|C3.X|
The book of pages|Snap|Line1|Line2|Line3|Line4|Line5|C3.Y|
.
.
.
.
.
The song|Snap|Line1|Line2|Line3|Line4|Line5|C2.X|
The song|Snap|Line1|Line2|Line3|Line4|Line5|C2.Y|
Example
<Rating>
<C1>
<elt>
<X></X>
<X></X>
</elt>
<elt>
<elt>
</C1>
<C2>
<elt>
<elt>
<elt>
</C2>
<C3>
<elt>
<elt>
<elt>
</C3>
</Rating>
正如 ikegami 所建议的,最简单的方法是创建一个评级处理程序。但问题是解析它所花费的时间。我要解析的文件是 300 mb,有大约 20 个这样的例程,比如评级。所以我把大套路解析一次,然后把大套路的一部分解析20次。还有另一种方法吗?是否有另一个 XML 模块比 XML::Twig 更有用?
因此您希望节点匹配 XPath
descendant:*[count(*)=0]
又名
.//*[count(*)=0]
相对于 elt
元素。我用XML::LibXML,所以我会
$elt_node->findnodes("descendant:*[count(*)=0]")
XML::Twig 应该可以提供类似的解决方案。 (确实有 findnodes
。)
ug,我忘了 XML::Twig 对 XPath 的支持有多糟糕。它不知道 count
,并且 *
匹配非元素。没问题,我们只需要自己完成工作即可。
use strict;
use warnings;
use feature qw( say );
use XML::Twig qw( );
my @eles = qw( Book Snap Line1 Line2 Line3 Line4 Line5 C1 C2 C3 );
my $twig = XML::Twig->new(
twig_handlers => {
'/APP:Report/library/elt' => sub {
my ($twig, $ele) = @_;
my %row =
map { $_->name() => $_->text() // '' }
# $ele->findnodes("descendant:*[count(*)=0]")
grep { $_->name() ne '#PCDATA' && ( grep { $_->name() ne '#PCDATA' } $_->children ) == 0 }
$ele->descendants();
say join '|', @row{@eles};
$twig->purge(); # Free unneeded memory.
},
},
);
say join '|', @eles;
$twig->parsefile('my_big.xml');
输出:
Book|Snap|Line1|Line2|Line3|Line4|Line5|C1|C2|C3
The book of pages||The Beginning|We ceased to exist|Accept it|Now we live|We reject it|6.1|8.9|9.4
The song||This is how we do it|I hope this works|Please do|Begging you|Bye|2.3|9.9|4.5