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

Hi,

I am trying to add attributes to a tag as per my requirement. But in the result It is not in the same order as I added attributes. Please let me know how can I add attributes and get the result in the same order. My code is as below. Thank you in advance.

#!/usr/bin/perl use strict; use warnings; use XML::Twig; my $tagname="ait:date-delivered"; my $att1="month"; my $att2="year"; my $att3="day"; changeTagAttrOrder(); sub changeTagAttrOrder { my $t= XML::Twig->new( output_filter=>'safe', twig_handlers => { '_default_' => sub { }, *[@att='type'] => \&changeTagAttrOrderH +andler; }, pretty_print => 'indented', keep_atts_order => 1,#Tie::IxHash needs to be installed fo +r this option to be available. ); $t->parse(\*DATA); $t->print; $t->purge; }#end of changeTagAttrOrder sub changeTagAttrOrderHandler { my( $t,$rootElt)= @_; my $curEltPath = $rootElt->path; if($curEltPath =~ m/$tagname/){ print "Found tag $tagname in path $curEltPath\n"; print $rootElt->att($att1)."\t".$rootElt->att($att2)."\t".$roo +tElt->att($att3); my $att1Val=$rootElt->att($att1); my $att2Val=$rootElt->att($att2); my $att3Val=$rootElt->att($att3); $rootElt->del_atts; print "after delete \tAttributes are ::".join(",",$rootElt->a +tt_names())."\n"; $rootElt->set_atts( { $att1 => $att1Val, $att2 => $att2Val, $a +tt3 => $att3Val}); print "after new set \tAttributes are ::".join(",",$rootElt->a +tt_names())."\n"; } }#end of changeTagAttrOrderHandler __DATA__ <item> <ait:process-info> <ait:date-delivered year="2010" month="02" day="09"/> <ait:date-sort year="2008" month="1" day="1"/> <ait:status type="core" state="new" stage="S300"/> </ait:process-info> </item>

Replies are listed 'Best First'.
Re: set attributes to an element in user defined order
by ambrus (Abbot) on Mar 05, 2010 at 07:31 UTC

    How you ever got that code to even compile with this line in it I don't get (quotes are missing and the semicolon should be a comma)

    *[@att='type'] => \&changeTagAttrOrderH +andler;

    But anyway, your problem might be that this line

    $rootElt->set_atts( { $att1 => $att1Val, $att2 => $att2Val, $a +tt3 => $att3Val});
    makes an ordinary hash (not an IxHash) and passes it to the set_atts method, so the order of the elements is lost.

    As a simple standalone example, this code gives the attributes in a fixed order but it doesn't if you comment out the line with the arrow

    use warnings; use strict; use XML::Twig; use Tie::IxHash; my $tw = XML::Twig->new("keep_atts_order", 1); my %atts; tie %atts, Tie::IxHash::; # <----- %atts = ("year", 2010, "month", 3, "day", 5); $tw->set_root(XML::Twig::Elt->new("date", \%atts)); $tw->flush; print "\n"; __END__

    Alternately use the set_att method like this:

    use warnings; use strict; + use XML::Twig; + my $tw = XML::Twig->new("keep_atts_order", 1); $tw->set_root(my $de = XML::Twig::Elt->new("date")); $de->set_att("year", 2010, "month", 3, "day", 5); $tw->flush; print "\n"; __END__
    (But note that set_att does not delete the existing attributes, so you may need to call del_atts first.)
Re: set attributes to an element in user defined order
by NiJo (Friar) on Mar 02, 2010 at 19:11 UTC
    Your object is based on a hash, as most objects and external modules do. So the same effects apply, including the return of key/value pairs in a pseudo random order. You have to readjust your expectations or use a different data model. This means abandoning use of XML::Twig.
Re: set attributes to an element in user defined order
by stefbv (Priest) on Mar 05, 2010 at 07:30 UTC

    I made the code to run but it doesn't work :)

    I mean that it doesn't do what it's suppose to do, this is the output:

    after delete Attributes are: after new set Attributes are: day,month,year <item> ... <ait:date-delivered month="02" day="09" year="2010"/> ... </item>

    It's funny but the order is different for all tree steps, in the original doc, aftet delete and insert an in the resulting doc.

    On the other hand the man page say:
    'keep_atts_order' allows outputting the attributes in the same order as they were in the original document.

    Does this mean XML::Twig it's not designed to work this way?

    #!/usr/bin/perl use strict; use warnings; use XML::Twig; changeTagAttrOrder(); sub changeTagAttrOrder { my $t = XML::Twig->new( output_filter=>'safe', twig_handlers => { 'ait:date-delivered' => \&changeTagAttrOrderHandler, }, pretty_print => 'indented', keep_atts_order => 1, ); $t->parse(\*DATA); $t->print; $t->purge; }#end of changeTagAttrOrder sub changeTagAttrOrderHandler { my( $t,$rootElt)= @_; my $curEltPath = $rootElt->path; my $att1Val = $rootElt->att('month'); my $att2Val = $rootElt->att('year'); my $att3Val = $rootElt->att('day'); $rootElt->del_atts; print "after delete\n Attributes are: ".join(',',$rootElt->att_names())."\n"; # $rootElt->set_atts( # { month => $att1Val, year => $att2Val, day => $att3Val}); $rootElt->set_att(day => $att3Val); $rootElt->set_att(month => $att1Val); $rootElt->set_att(year => $att2Val); print "after new set\n Attributes are: ".join(',',$rootElt->att_names())."\n"; }#end of changeTagAttrOrderHandler __DATA__ <item> <ait:process-info> <ait:date-delivered year="2010" month="02" day="09"/> <ait:date-sort year="2008" month="1" day="1"/> <ait:status type="core" state="new" stage="S300"/> </ait:process-info> </item>

    Regards, Stefan

Re: set attributes to an element in user defined order
by Jenda (Abbot) on Mar 03, 2010 at 08:43 UTC

    The attribute order has no meaning in XML and I doubt there is a way to instruct XML::Twig to output them in a specific order.

    Jenda
    Enoch was right!
    Enjoy the last years of Rome.

      You've fallen into a trap. Read the post again. It tries to use the keep_atts_order option of XML::Twig, and the whole purpose of that option is to be able to output the attributes in a particular order.