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

Hi, I would like to sort whole xml tree i.e attribute as well as on text of all sub elements. I have attached my code below. But the problem here is... attribute sort is fine, where as the sub element sorting has done only for the first set. Could you please help me to resolve this ASAP. It will be of great help. Thank you in advance

#!/bin/perl -w use strict; use XML::Twig; my $twig= XML::Twig->new(pretty_print=>'indented'); $twig->parse(\*DATA); my $root=$twig->root; $twig->root->first_child->sort_children( sub { $_->{'att'}->{"type"}}) +; $twig->root->first_child->first_child->sort_children( sub { $_->text}) +; #$twig->root->sort_children_on_att("type"); #$twig->root->sort_children_on_field('mainterm'); $twig->print; __DATA__ <enhancement> <descriptorgroup> <descriptors type="MED" controlled="y"> <descriptor> <mainterm weight="a">plague</mainterm> <mainterm>disease</mainterm> <mainterm>pestilence</mainterm> </descriptor> </descriptors> <descriptors type="DRG" controlled="y"> <mainterm>panadol</mainterm> <mainterm weight="a">zorro</mainterm> <mainterm>xenon</mainterm> <mainterm weight="a">aspirin</mainterm> </descriptors> </descriptorgroup> </enhancement>

output I got was as below

---------- perl compile ---------- <enhancement> <descriptorgroup> <descriptors controlled="y" type="DRG"> <mainterm weight="a">aspirin</mainterm> <mainterm>panadol</mainterm> <mainterm>xenon</mainterm> <mainterm weight="a">zorro</mainterm> </descriptors> <descriptors controlled="y" type="MED"> <descriptor> <mainterm weight="a">plague</mainterm> <mainterm>disease</mainterm> <mainterm>pestilence</mainterm> </descriptor> </descriptors> </descriptorgroup> </enhancement> Output completed (3 sec consumed) - Normal Termination

Replies are listed 'Best First'.
Re: twig inbuilt methods to sort whole xml tree
by NetWallah (Canon) on Mar 07, 2010 at 23:45 UTC
    How about this:
    $root->first_child->sort_children_on_att("type"); sort_my_kids($root); $twig->print; #---------- sub sort_my_kids{ my $me = shift; $me->sort_children_on_value; foreach my $kid($me->children){ sort_my_kids($kid); # Recursive } }
    Prints:
    <enhancement> <descriptorgroup> <descriptors controlled="y" type="DRG"> <mainterm weight="a">aspirin</mainterm> <mainterm>panadol</mainterm> <mainterm>xenon</mainterm> <mainterm weight="a">zorro</mainterm> </descriptors> <descriptors controlled="y" type="MED"> <descriptor> <mainterm>disease</mainterm> <mainterm>pestilence</mainterm> <mainterm weight="a">plague</mainterm> </descriptor> </descriptors> </descriptorgroup> </enhancement>

         Theory is when you know something, but it doesn't work.
        Practice is when something works, but you don't know why it works.
        Programmers combine Theory and Practice: Nothing works and they don't know why.         -Anonymous

      Thanks a lot... Great!!!! Solution is perfectly working. I have been strugling to solve from past 3 days. I am very thankful to you.

        Hi, I just changed the input as below.

        __DATA__ <enhancement> <descriptorgroup> <descriptors type="MED" controlled="y"> <descriptor> <mainterm weight="a">plague</mainterm> <mainterm>disease</mainterm> <mainterm>pestilence</mainterm> <link>f</link> <link>C</link> <link>M</link> </descriptor> </descriptors> <descriptors type="DRG" controlled="y"> <mainterm>panadol</mainterm> <mainterm weight="a">zorro</mainterm> <mainterm>xenon</mainterm> <mainterm weight="a">aspirin</mainterm> <link>b</link> <link>P</link> <link>z</link> </descriptors> </descriptorgroup> </enhancement>

        Most of it is going fine, but one thing I noticed is that it’s moving the position of “mainterm” as well. This won’t work because the xsd/dtd says that <mainterm> must come first, and then the <linkterm>s which are related to it. What is happening at the moment is that it is arrange ALL the tags alphabetically, <mainterm> and <linkterm>. How can this be controlled by the code?

        <enhancement> <descriptorgroup> <descriptors controlled="y" type="DRG"> <link>P</link> <mainterm weight="a">aspirin</mainterm> <link>b</link> <mainterm>panadol</mainterm> <mainterm>xenon</mainterm> <link>z</link> <mainterm weight="a">zorro</mainterm> </descriptors> <descriptors controlled="y" type="MED"> <descriptor> <link>C</link> <link>M</link> <mainterm>disease</mainterm> <link>f</link> <mainterm>pestilence</mainterm> <mainterm weight="a">plague</mainterm> </descriptor> </descriptors> </descriptorgroup> </enhancement>
    A reply falls below the community's threshold of quality. You may see it by logging in.