0

I have the following XML

<?xml version="1.0" encoding="UTF-8"?>  
  <Objects >
    <Item1 elemId="id1" name="view" sort_id="3">
    </Item1>
    <Item2 elemId="id3" name="view" sort_id="4" >
    </Item2>
    <Item3 elemId="id5" name="view" sort_id="2">
    </Item3>
    <Item4 elemId="id9" name="view" sort_id="1">
    </Item4>
  </Objects>

I want to sort this data by the attribute sort_id to get the following:

<?xml version="1.0" encoding="UTF-8"?>  
  <Objects >
    <Item4 elemId="id9" name="view" sort_id="1">
    </Item4>
    <Item3 elemId="id5" name="view" sort_id="2">
    </Item3>
    <Item1 elemId="id1" name="view" sort_id="3">
    </Item1>
    <Item2 elemId="id3" name="view" sort_id="4" >
    </Item2>
  </Objects>

I know that I can't do this in XML::Simple, but I heard that I can sort with XML::LibXML. I couldn't find the solution.

2
  • 1
    First, you need to come to terms with the fact that you won't be sorting XML: You will be parsing the XML into a data structure and produce XML sorted by your criterion. Commented Dec 4, 2016 at 17:41
  • 3
    "I couldn't find the solution." Well, what have you tried so far, and what part of it didn't work? Commented Dec 4, 2016 at 19:05

1 Answer 1

5

There is nothing built into XML::LibXML that specifically provides for sorting elements, but it is simple to do using the available API

Something like this will do what you want. Unfortunately XML::LibXML isn't very good at producing neat output, although it is perfectly well-formed and valid. If you want something prettier then you should look at XML::LibXML::PrettyPrint, which will do this for you

use strict;
use warnings 'all';

use XML::LibXML;

my $doc = XML::LibXML->load_xml(location => 'sort_xml.xml');

my ($objects) = $doc->findnodes('/Objects');

my @items = $objects->findnodes('*');
@items = sort {
    $a->getAttribute('sort_id') <=> $b->getAttribute('sort_id')
} @items;

$objects->removeChildNodes;
$objects->appendChild( $_ ) for @items;

print $doc;

output

<?xml version="1.0" encoding="UTF-8"?>
<Objects><Item4 elemId="id9" name="view" sort_id="1">
    </Item4><Item3 elemId="id5" name="view" sort_id="2">
    </Item3><Item1 elemId="id1" name="view" sort_id="3">
    </Item1><Item2 elemId="id3" name="view" sort_id="4">
    </Item2></Objects>

Update

To use XML::LibXML::PrettyPrint, you need to add

use XML::LibXML::PrettyPrint;

at the top of the program, and replace

print $doc;

with

my $pp = XML::LibXML::PrettyPrint->new(indent_string => "  ");
$pp->pretty_print($doc);
print $doc;

output

<?xml version="1.0" encoding="UTF-8"?>
<Objects>
  <Item4 elemId="id9" name="view" sort_id="1"/>
  <Item3 elemId="id5" name="view" sort_id="2"/>
  <Item1 elemId="id1" name="view" sort_id="3"/>
  <Item2 elemId="id3" name="view" sort_id="4"/>
</Objects>
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.