Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic

help to preserve the order of hash

by satzbu (Acolyte)
on Jun 23, 2010 at 17:32 UTC ( #846121=perlquestion: print w/replies, xml ) Need Help??

satzbu has asked for the wisdom of the Perl Monks concerning the following question:

This node falls below the community's threshold of quality. You may see it by logging in.

Replies are listed 'Best First'.
Re: help to preserve the order of hash
by almut (Canon) on Jun 23, 2010 at 18:29 UTC

    You could try

    #!/usr/bin/perl { package XML::Simple::Ordered; # subclass overriding new_hashref + method use base qw(XML::Simple); use Tie::IxHash; sub new_hashref { my $self = shift; my %hash; tie %hash, 'Tie::IxHash', @_; return \%hash; } } package main; my $simple = XML::Simple::Ordered->new(); my $data = $simple->XMLin($file);

    new_hashref is a documented hook, and the above does in fact seem to produce ordered results for simple inputs.  Still, no guarantees whatsoever!

    Update: actually, new_hashref isn't being used consistently, so some hashes are still not ordered... (in the case of tags without any attributes)

    To fix this issue, you'd unfortunately have to patch the source file XML/

    sub collapse { my $self = shift; # Start with the hash of attributes my $attr = shift; $attr = $self->new_hashref() unless %$attr; # <-- add this line

    That's ugly, but with this additional change, most typical cases should work.

Re: help to preserve the order of hash
by herveus (Parson) on Jun 23, 2010 at 17:46 UTC

    Let me call your attention to the documentation for XML::Simple, in particular the part where it notes some assumptions that must hold. Specifically, the part where it says "You don't mind that when things get slurped into a hash, the order is lost".

    It notes that "'ll probably outgrow these assumptions fairly quickly". You probably need to switch to another module.

      > You probably need to switch to another module.

      actually there are options like "force array".

      Cheers Rolf


        True, but it does not appear to do what the OP needs. As I read the POD, it appears that the top level structure returned by XMLin is always a hashref. At any given level, the keys in the hash are the distinct tags that appear at that level. If there are multiple instances of a tag, each instance is an element in an array of hashes.

        ForceArray simply forces that behavior even if there is only one instance of the tag. It does not appear that there is any way to make XMLin return an arrayref.

        The POD does describe the limitations, and the OP has run smack into one of them. The suggested course of action is "use a different module". Hacking (for some value of "hacking") XML::Simple to use Tie::IxHash internally is certainly one way to go there; the OP will have to decide which approach will work best for this problem.

Re: help to preserve the order of hash
by LanX (Sage) on Jun 23, 2010 at 17:45 UTC
Re: help to preserve the order of hash
by ikegami (Pope) on Jun 23, 2010 at 19:27 UTC

    You're tying %xhash, a hash unrelated to XML::Simple or what it returns. You would need to tie the multiple hashes XML::Simple creates, and you would have to do so before it populates them. This would involve changing XML::Simple*, and it would create a significant performance hit.

    Of course, the better answer is to not use a hash in the first place. See ForceArray, or use a better parser.

    * — almut showed a way of doing this non-obtrusively.

Re: help to preserve the order of hash
by Anonymous Monk on Jun 23, 2010 at 17:43 UTC

    Hashes have no order. If order is important, don't tie to a hash, use an array instead.

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://846121]
Approved by herveus
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (4)
As of 2021-12-03 14:02 GMT
Find Nodes?
    Voting Booth?
    R or B?

    Results (29 votes). Check out past polls.