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

Hello. I need to define a xml config file and read the parameters, attributes, values and assign them to a hash. I understood the part of XML::Simple and XMLin() to read the XML file, but I am having trouble in reading the elements based on attributes.

<list> <value category="default"> <parameter instance="0">nameoftheparameter</parameter> <value>1</value> </value> <value category="special"> <parameter instance="0">nameofparameter1</parameter> </value> </list>

I want to access the "value" based on the attribute "category" and also in case I have multiple parameters with different "instances". Please help.

Replies are listed 'Best First'.
Re: XML Parsing
by tobias_hofer (Friar) on Jan 31, 2013 at 10:21 UTC
    When reading-in xml the XML-Simple provides the xml as a hash-structure.
    Using Data::Dumper to give a print-out on command line.
    Thus you can easily see how to access the elements.
    Some xml-tags which may occur more than once are grouped into an array as far as I remember..
    IMHO Data::Dumper is an easy way of exploring structures :-)
    Hope this helps!

    Best regards
    Tobias
Re: XML Parsing
by tmharish (Friar) on Jan 31, 2013 at 11:21 UTC

    You can use XML::Smart to do this like so:

    my $xml_obj = new XML::Smart( $xml ) ; my $hash_when_cat_eq_special = ( $xml_obj->{list}{value}( 'category', +'eq', 'special' )->pointer() );
    $hash_when_cat_eq_special will contain: { "/nodes" => { parameter => 1 }, "/order" => ["category", "parameter"], "category" => "special", "parameter" => { "/order" => ["instance", "CONTENT"], "CONTENT" => "\n nameofparameter1\n + ", "instance" => 0, }, }

    Of course you can get more specific as follows:

    my $xml_obj = new XML::Smart( $xml ) ; my $param_contents = $xml_obj->{list}{value}( 'category', 'eq', 'speci +al' )->{parameter}->content();
    $param_contents will contain: "nameofparameter1"
      This way of invoking the constructor can be problematic:
      my $xml_obj = new XML::Smart( $xml ) ;
      See the section "Indirect Object Syntax" in Invoking Class Methods
        Do you really use
        'XML::Smart'->new
        or
        XML::Smart::->new
        or
        new XML::Smart::
        ?
        لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
      First of all thank you Harish. I got the output as suggested. Say for example I had few more child elements under value tag, can I use foreach and extract the elements/sub-elements into a hash/array? Could you give me any sample code to put the contents of $hash_when_cat_eq_special in an hash? Thanks.

        Quite simply $hash_when_cat_eq_special is a pointer to a hash. So you can do your normal hash operations on it. The ->pointer() function returns this for you.

        In terms of the foreach:

        foreach my $elem ( @{ $xml_obj->{list}{value} } ) { $hash_of_subtree = $elem->pointer() ; }

        The advantage here is that $xml_obj, $xml_obj->{list} ... are all Objects of type XML::Smart and can always be used as either a hash OR an array.

        To extract your data you can simply use the 'pointer' function ( $xml_smart_obj->pointer() )that will return the hash structure or the 'content' function ( $xml_smart_obj->content() ) that will return the contents of a node.

Re: XML Parsing
by Anonymous Monk on Jan 31, 2013 at 10:21 UTC
Re: XML Parsing
by vmallya (Initiate) on Jan 31, 2013 at 13:09 UTC
    I used the XML::Smart option. Thanks to TM Harish. I see a warning message. Use of uninitialized value $data in length at /usr/local/lib/perl5/site_perl/5.10.0/XML/Smart/Tree.pm line 159. May be the XML Smart package had some unassigned variable.

      Yes indeed!

      Will fix in next update due in a couple of days. Thanks for the report and do report anything else you find either here or on CPAN's RT.

      Full details whats going on is on this PerlMonks thread.