perl:如何顺序解析xml文件

时间:2011-12-24 19:19:56

标签: perl xml-parsing

我有一个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'相对于数据结构起点的相对位置。

我想找出每个元素的偏移量。

我尝试搜索perl XML解析器,它允许我按顺序解析XML文件,类似于'getnexttag()'类型的功能,但找不到任何。

以编程方式执行此操作的最佳方法是什么?如果不是perl,那么哪种其他语言最适合做这项工作?

3 个答案:

答案 0 :(得分:3)

你需要使用带有适当回调的流式解析器,当涉及到更大的数据集时,这也将提高解析速度(并且如果正确完成,可以减少内存消耗),这是一个很好的/ 很棒的事情。

我建议您使用XML::SAX,可在以下链接中找到该模块的介绍:

start_element提供回调,这样您就可以一次读取每个元素的值。


你能给我一个简单的例子吗?

是的,我已经拥有了!的; - )

下面的代码片段将解析所提供的数据OP并打印每个元素的名称,以及属性键/值。

理解起来应该很容易,但如果您有任何问题,请随时将其添加为评论,我会更新此帖子并提供更详细的信息。

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不满意,还有其他模块可用吗?

是的,有很多可供选择。阅读以下列表并选择适合您特定问题的列表:


不同的解析方法有什么区别?

我还建议阅读以下有关XML解析的常见问题解答。它将提出使用树解析器(例如XML :: Parser :: Simple)或流解析器的Pro和Con:

答案 1 :(得分: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"/>"

答案 2 :(得分:1)

以下是使用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