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,该模块的介绍可在以下链接中找到:

XML::SAX::Intro

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 文件的主要内容,如果未能解决你的问题,请参考以下文章

在 Perl 中按顺序打印哈希键

Perl,如何解析 XML 文件,xpath

顺序芹菜任务执行

XML,DTD:如何使顺序不重要

如何从OpenCV的目录中按顺序读取文件?

如何按字母顺序对 DBML 对象进行排序?