列出文档元素的所有 child 个节点
Listing all the child nodes of document element
我有一个非常大的 XML 文件,我想列出文档元素的所有 child 节点。
我正在使用下面的代码,它工作正常,但处理文件需要很长时间,而且它正在从不需要的文档元素中获取数据:
use XML::Simple;
my $xml = XML::Simple->new();
my $d = $xml->XMLin("sample.xml");
my @arr = keys %$d;
print "@arr\n";
示例XML:
<?xml version="1.0" encoding="ISO-8859-15"?>
<document version="1.0" createdAt="2017-03-31T11:41:34">
<TITLE>Computer Parts</TITLE>
<PART001>
<ITEM>Motherboard</ITEM>
<MANUFACTURER>ASUS</MANUFACTURER>
<MODEL>P3B-F</MODEL>
<COST> 123.00</COST>
</PART001>
<PART002>
<ITEM>Video Card</ITEM>
<MANUFACTURER>ATI</MANUFACTURER>
<MODEL>All-in-Wonder Pro</MODEL>
<COST> 160.00</COST>
</PART002>
<PART003>
<ITEM>Sound Card</ITEM>
<MANUFACTURER>Creative Labs</MANUFACTURER>
<MODEL>Sound Blaster Live</MODEL>
<COST> 80.00</COST>
</PART003>
<PART004>
<ITEM>14 inch Monitor</ITEM>
<MANUFACTURER>LG Electronics</MANUFACTURER>
<MODEL> 995E</MODEL>
<COST> 290.00</COST>
</PART004>
</document>
预期输出:
标题,
零件001,
PART002,
PART003,
PART004
任何人都可以建议一种更快更好的方法来获得所需的输出吗?
您可以使用 XML::Twig
,根据其 documentation,它是一个 perl 模块,用于以树模式处理巨大的 XML 文档。
这是一个适合您的用例的示例:
use feature qw(say);
use XML::Twig;
XML::Twig->new(twig_handlers => {
'document/*' => sub {
say $_->name; # print out the element name
$_->purge; # remove the entire element from memory
}
})->parsefile('sample.xml');
与示例文档一起使用时,打印出:
TITLE
PART001
PART002
PART003
PART004
使用流式解析器可能会更快。
通过使用 XML::LibXML 和 XPath
。
use 5.014;
use warnings;
use XML::LibXML;
my $file = 'xml';
my $dom = XML::LibXML->load_xml(location => $file);
for my $child ($dom->findnodes( q{//document/*} )) {
say $child->nodeName();
}
产出
TITLE
PART001
PART002
PART003
PART004
或者仅针对这种情况,如果您只需要 PART
s
for my $part ($dom->findnodes( q{//*[contains(name(),'PART')]} )) {
say $part->nodeName();
}
产出
PART001
PART002
PART003
PART004
编辑: 使用 pull 解析器(不会将整个 xml 加载到内存中):
use 5.014;
use warnings;
use XML::LibXML::Reader qw(XML_READER_TYPE_ELEMENT);
my $file="xml";
my $reader = XML::LibXML::Reader->new(location => $file) or die "problem $!";
while($reader->read()) {
if( $reader->depth == 1 && $reader->nodeType == XML_READER_TYPE_ELEMENT ) {
say $reader->name;
}
}
TITLE
PART001
PART002
PART003
PART004
EDIT2
use 5.014;
use warnings;
use XML::LibXML::Reader qw(XML_READER_TYPE_ELEMENT);
my $file="xml";
my $reader = XML::LibXML::Reader->new(location => $file) or die "problem $!";
my $indoc;
while($reader->read()) {
# sets the flag in youre inside the <document>
if( $reader->name eq 'document' ) {
$indoc = $reader->nodeType == XML_READER_TYPE_ELEMENT ? 1 : 0;
}
# all nodes with level 1 if they're inside of the <document>
if( $indoc && $reader->depth == 1 && $reader->nodeType == XML_READER_TYPE_ELEMENT ) {
say $reader->name;
}
}
我有一个非常大的 XML 文件,我想列出文档元素的所有 child 节点。 我正在使用下面的代码,它工作正常,但处理文件需要很长时间,而且它正在从不需要的文档元素中获取数据:
use XML::Simple;
my $xml = XML::Simple->new();
my $d = $xml->XMLin("sample.xml");
my @arr = keys %$d;
print "@arr\n";
示例XML:
<?xml version="1.0" encoding="ISO-8859-15"?>
<document version="1.0" createdAt="2017-03-31T11:41:34">
<TITLE>Computer Parts</TITLE>
<PART001>
<ITEM>Motherboard</ITEM>
<MANUFACTURER>ASUS</MANUFACTURER>
<MODEL>P3B-F</MODEL>
<COST> 123.00</COST>
</PART001>
<PART002>
<ITEM>Video Card</ITEM>
<MANUFACTURER>ATI</MANUFACTURER>
<MODEL>All-in-Wonder Pro</MODEL>
<COST> 160.00</COST>
</PART002>
<PART003>
<ITEM>Sound Card</ITEM>
<MANUFACTURER>Creative Labs</MANUFACTURER>
<MODEL>Sound Blaster Live</MODEL>
<COST> 80.00</COST>
</PART003>
<PART004>
<ITEM>14 inch Monitor</ITEM>
<MANUFACTURER>LG Electronics</MANUFACTURER>
<MODEL> 995E</MODEL>
<COST> 290.00</COST>
</PART004>
</document>
预期输出: 标题, 零件001, PART002, PART003, PART004
任何人都可以建议一种更快更好的方法来获得所需的输出吗?
您可以使用 XML::Twig
,根据其 documentation,它是一个 perl 模块,用于以树模式处理巨大的 XML 文档。
这是一个适合您的用例的示例:
use feature qw(say);
use XML::Twig;
XML::Twig->new(twig_handlers => {
'document/*' => sub {
say $_->name; # print out the element name
$_->purge; # remove the entire element from memory
}
})->parsefile('sample.xml');
与示例文档一起使用时,打印出:
TITLE
PART001
PART002
PART003
PART004
使用流式解析器可能会更快。
通过使用 XML::LibXML 和 XPath
。
use 5.014;
use warnings;
use XML::LibXML;
my $file = 'xml';
my $dom = XML::LibXML->load_xml(location => $file);
for my $child ($dom->findnodes( q{//document/*} )) {
say $child->nodeName();
}
产出
TITLE
PART001
PART002
PART003
PART004
或者仅针对这种情况,如果您只需要 PART
s
for my $part ($dom->findnodes( q{//*[contains(name(),'PART')]} )) {
say $part->nodeName();
}
产出
PART001
PART002
PART003
PART004
编辑: 使用 pull 解析器(不会将整个 xml 加载到内存中):
use 5.014;
use warnings;
use XML::LibXML::Reader qw(XML_READER_TYPE_ELEMENT);
my $file="xml";
my $reader = XML::LibXML::Reader->new(location => $file) or die "problem $!";
while($reader->read()) {
if( $reader->depth == 1 && $reader->nodeType == XML_READER_TYPE_ELEMENT ) {
say $reader->name;
}
}
TITLE
PART001
PART002
PART003
PART004
EDIT2
use 5.014;
use warnings;
use XML::LibXML::Reader qw(XML_READER_TYPE_ELEMENT);
my $file="xml";
my $reader = XML::LibXML::Reader->new(location => $file) or die "problem $!";
my $indoc;
while($reader->read()) {
# sets the flag in youre inside the <document>
if( $reader->name eq 'document' ) {
$indoc = $reader->nodeType == XML_READER_TYPE_ELEMENT ? 1 : 0;
}
# all nodes with level 1 if they're inside of the <document>
if( $indoc && $reader->depth == 1 && $reader->nodeType == XML_READER_TYPE_ELEMENT ) {
say $reader->name;
}
}