如何使用XML :: Simple读取XML文件中的值的顺序?

时间:2010-09-13 11:54:31

标签: xml perl hash

我正在使用XML :: Simple来解析XML文件。代码在下面给出了XML文件,

use Tie::IxHash;

tie %$data, "Tie::IxHash";

use XML::Simple;
use Data::Dumper;

$xml = new XML::Simple;
$data = $xml->XMLin("ship_order.xml");
print Dumper($data);

XML文件,(ship_order.xml)

<?xml version="1.0" encoding="UTF-8" ?> 

<shipment>
    <shiptoaddress>
        <name>Prasad</name> 
        <address>AnnaNagar</address> 
    </shiptoaddress> 
    <items>
        <quantity>5</quantity> 
        <price>100</price> 
    </items> 
    <items>
        <quantity>6</quantity> 
        <price>50</price> 
    </items>
    <num_of_items>2</num_of_items>
</shipment>

即使我使用Tie :: IxHash模块,输出也没有按顺序排列。

我的输出:

$VAR1 = {
          'num_of_items' => '2',
          'shiptoaddress' => {
                             'name' => 'Prasad',
                             'address' => 'AnnaNagar'
                           },
          'items' => [
                     {
                       'quantity' => '5',
                       'price' => '100'
                     },
                     {
                       'quantity' => '6',
                       'price' => '50'
                     }
                   ]
        };

2 个答案:

答案 0 :(得分:6)

啊,但你没有使用Tie::IxHash。或者更确切地说,您开始使用Tie::IxHash然后销毁它:

$data = $xml->XMLin("ship_order.xml");

此行会丢弃您创建的哈希引用,并将方法调用中的一个引用分配给$data

如果你关心项目的顺序(你可能不应该这样做,因为任何体面的XML格式都会包含一个告诉你顺序的属性),你需要使用一个返回一个对象的解析器,而不是数据结构。该对象将知道项目的顺序,并为您提供返回它们的children方法。

或者,您可以自己构建数据结构:

#!/usr/bin/perl

use strict;
use warnings;

use XML::Twig;

my $shipment;
my $t = XML::Twig->new(
    twig_handlers => {
        shiptoaddress => sub {
            my ($t, $elt) = @_;

            $shipment->{name}    = $elt->first_child("name")->text;
            $shipment->{address} = $elt->first_child("address")->text;

            $t->purge;
        },
        items => sub {
            my ($t, $elt) = @_;

            push @{$shipment->{items}}, {
                quantity => $elt->first_child("quantity")->text,
                price    => $elt->first_child("price")->text,
            };

            $t->purge;
        },
    },
);

$t->parse(join "", <DATA>); #FIXME: use parsefile later

use Data::Dumper;
print Dumper $shipment;

__DATA__
<?xml version="1.0" encoding="UTF-8" ?> 

<shipment>
    <shiptoaddress>
        <name>Prasad</name> 
        <address>AnnaNagar</address> 
    </shiptoaddress> 
    <items>
        <quantity>5</quantity> 
        <price>100</price> 
    </items> 
    <items>
        <quantity>6</quantity> 
        <price>50</price> 
    </items>
    <num_of_items>2</num_of_items>
</shipment>

答案 1 :(得分:3)

您可以考虑继承XML::Simple并覆盖使用Tie::IxHash创建哈希的必要方法。

但请认真考虑XML::Simple的作者在此帖子中CPAN forum给出的答案:how to preserve XML::Simple element order ...

  

保留元素顺序不是,也永远不会是XML :: Simple的一个特性。对于某些XML文档类型,您可以通过继承XML :: Simple并覆盖new_hashref()方法来提供绑定到Tie :: IxHash的hashref。这可以解决ABC案件,但不会解决ABA案件。   简短的回答是,如果您关心元素顺序,那么您不应该使用XML :: Simple。 XML :: LibXML是一个很好的选择,对于许多用例而言,实际上并不比XML :: Simple更难使用 - 如[1]中所述

还有他在code中的内容:

##############################################################################
# Method: new_hashref()
#
# This is a hook routine for overriding in a sub-class.  Some people believe
# that using Tie::IxHash here will solve order-loss problems.
# 

sub new_hashref {
  my $self = shift;

  return { @_ };
}

[1] - Stepping up from XML::Simple to XML::LibXML