perl:如何按顺序解析 xml 文件
Posted
技术标签:
【中文标题】perl:如何按顺序解析 xml 文件【英文标题】:perl: how to parse an xml file sequentially 【发布时间】:2012-01-27 10:13:46 【问题描述】:我有一个 XML 文件,它描述了我可以在 UDP 通道上交换的数据结构。 例如: 这是描述我的数据结构的输入 XML 文件。
<ds>
<uint32 name='a'/>
<uint32 name='b'/>
<string name='c'/>
<int16 name='d'/>
<uint32 name='e'/>
</ds>
使用 perl 的 XML 解析这个 XML 文件:简单,允许我生成以下哈希
$VAR1 =
'uint32' =>
'e' => ,
'a' => ,
'b' =>
,
'int16' =>
'name' => 'd'
,
'string' =>
'name' => 'c'
;
如您所见,解析后我无法确定字段“e”相对于数据结构开头的相对位置。
我想找出每个元素的偏移量。
我尝试搜索允许我按顺序解析 XML 文件的 perl XML 解析器,类似于“getnexttag()”之类的功能,但找不到。
以编程方式执行此操作的最佳方法是什么?如果不是 perl,那么哪种其他语言最适合做这项工作?
【问题讨论】:
【参考方案1】:您需要使用带有适当回调的流式解析器,这也将提高解析速度(如果操作正确,还可以减少内存消耗),这是一个很好的/太棒了的东西。
我推荐您使用XML::SAX
,该模块的介绍可在以下链接中找到:
为start_element
提供回调,这样你可以一次读取每个元素的值。
你能给我写一个简单的例子吗?
是的,我已经有了! ;-)
下面的sn-p会解析OP提供的数据,打印出每个元素的名字,以及属性key/value。
这应该很容易理解,但如果您有任何问题,请随时将它们添加为评论,我会更新这篇文章并提供更详细的信息。
use warnings;
use strict;
use XML::SAX;
my $parser = XML::SAX::ParserFactory->parser(
Handler => ExampleHandler->new
);
$parser->parse_string (<<EOT
<ds>
<uint32 name='a'/>
<uint32 name='b'/>
<string name='c'/>
<int16 name='d'/>
<uint32 name='e'/>
</ds>
EOT
);
# # # # # # # # # # # # # # # # # # # # # # # #
package ExampleHandler;
use base ('XML::SAX::Base');
sub start_element
my ($self, $el) = @_;
print "found element: ", $el->Name, "\n";
for my $attr (values %$el->Attributes)
print " '", $attr->Name, "' = '", $attr->Value, "'\n";
print "\n";
输出
found element: ds
found element: uint32
'name' = 'a'
found element: uint32
'name' = 'b'
found element: string
'name' = 'c'
found element: int16
'name' = 'd'
found element: uint32
'name' = 'e'
我对 XML::SAX 不满意,还有其他可用的模块吗?
是的,有很多选择。阅读以下列表并选择适合您特定问题的列表:
perl-xml.sourceforge.net/faq - cpan modules不同的解析方式有什么区别?
我还建议阅读以下有关 XML 解析的常见问题解答。它将提出使用树解析器(例如 XML::Parser::Simple)或流解析器的优缺点:
Perl-XML Frequently Asked Questions, Tree VS Stream【讨论】:
非常感谢您提供如此明确的答案。这很有帮助。【参考方案2】:用 Perl 肯定是可能的。
这是XML::LibXML
的示例:
use strict;
use warnings;
use feature 'say';
use XML::LibXML;
my $xml = XML::LibXML->load_xml( location => 'test.xml' );
my ( $dsNode ) = $xml->findnodes( '/ds' );
my @kids = $dsNode->nonBlankChildNodes; # The indices of this array will
# give the offset
my $first_kid = shift @kids; # Pull off the first kid
say $first_kid->toString; # "<uint32 name='a'/>"
my $second = $first_kid->nextNonBlankSibling();
my $third = $second->nextNonBlankSibling();
say $third->toString; # "<string name="c"/>"
【讨论】:
【参考方案3】:这里是一个使用XML::Twig
的例子
use XML::Twig;
XML::Twig->new( twig_handlers => 'ds/*' => \&each_child )
->parse( $your_xml_data );
sub each_child
my ($twig, $child) = @_;
printf "tag %s : name = %s\n", $child->name, $child->att->name;
这个输出:
tag uint32 : name = a
tag uint32 : name = b
tag string : name = c
tag int16 : name = d
tag uint32 : name = e
【讨论】:
以上是关于perl:如何按顺序解析 xml 文件的主要内容,如果未能解决你的问题,请参考以下文章