我如何维护XML文件中的值的顺序,并使用XML :: Simple读取它?

问题描述:

我正在使用XML :: Simple来解析XML文件。代码给出了下面的XML文件,我如何维护XML文件中的值的顺序,并使用XML :: Simple读取它?

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> 

输出不是为了未来,尽管我使用领带:: IxHash模块。

我的输出:

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

看到http://stackoverflow.com/questions/3650229/parsing-xml-file-in-perl-retain-sequence/3650297#3650297 – 2010-09-13 15:08:23

+0

当XML ::简单并不做你想要的东西,不要使用XML :: Simple。也就是说,当你使用* :: Simple模块来尝试做某件事情时,它不会这么做,这已经不再简单了。 – 2010-09-18 10:06:58

啊,但你不使用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> 
+0

您的条款“任何体面的XML格式将包含告诉您订单的属性”是非常错误的。 _XML本身默认为被订购._ – 2015-02-05 11:35:49

你可以考虑继承XML::Simple和overwritting创建与Tie::IxHash哈希必要的方法。

但是认真考虑这个答案由XML::Simple笔者在此线程CPAN forum给出:how to preserve XML::Simple element order ...

保留元素的顺序是不是也永远不会是XML的一个特点::简单。对于某些XML文档类型,您可以通过继承XML :: Simple并重写new_hashref()方法来提供与Tie :: IxHash绑定的hashref。这可以解决ABC案件,但它不会解决ABA案件。 简短的回答是,如果你关心元素顺序,那么你不应该使用XML :: Simple。 XML ::的libxml是一个很好的替代这对于很多使用情况实在是没有难度比XML使用::简单 - 在[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