tags:

views:

63

answers:

2

Considering that XML::Simple is the only module which can be used, I am stuck in retrieving the values from an XML. The structure goes below:

<testxml>
    <dev>
        <A>
            <tables>
                <datatables>
                    <table>a1</table>
                    <table>a2</table>
                    <table>a3</table>
                </datatables>
                <propertytables>
                    <table>A1</table>
                    <table>A2</table>
                </propertytables>
            </tables>
        </A>
        <B>
            <tables>
                <datatables>
                    <table>b1</table>
                    <table>b2</table>
                </datatables>
                <propertytables>
                    <table>B1</table>
                    <table>B2</table>
                </propertytables>
            </tables>
        </B>
    </dev>
</testxml>

The XMLOut is :

<opt>
  <dev name="A">
    <tables name="datatables">
      <table>a1</table>
      <table>a2</table>
      <table>a3</table>
    </tables>
    <tables name="propertytables">
      <table>A1</table>
      <table>A2</table>
    </tables>
  </dev>
  <dev name="B">
    <tables name="datatables">
      <table>b1</table>
      <table>b2</table>
    </tables>
    <tables name="propertytables">
      <table>B1</table>
      <table>B2</table>
    </tables>
  </dev>
</opt>

How do I retrieve the table array say for this condition:
dev name = "B" and tables name = "propertytables" # to output B1, B2

+2  A: 
$ref->{dev}{B}{tables}{propertytables}{table}

will be the reference and

@{ $ref->{dev}{B}{tables}{propertytables}{table} }

will be the list.

But really do

my $ref = XMLin( $some_source );
use Smart::Comments;
### $ref 

# ... OR ...

use Data::Dumper;
print Data::Dumper->Dump( [ $ref ], [ '*ref' ] );

to examine the structure to see what the pathing would be.

Axeman
+3  A: 

It's not true that XML::Simple is the only module to be used for this role. For something like this, I would used XML::LibXML with a bit of XPath.

But if you want to use XML::Simple, I find the best approach is to use Data::Dumper to dump the data structure that XML::Simple builds and to use that dump to work out the best way to walk the structure. In your case, it's pretty simple.

#!/usr/bin/perl

use strict;
use warnings;

use XML::Simple;
use Data::Dumper;

my $xml = do { local $/; <DATA> };

my $doc = XMLin($xml);

# print Dumper $doc;

my $dev = 'B';
my $table = 'propertytables';

foreach (@{$doc->{dev}{$dev}{tables}{$table}{table}}) {
  print "$_\n";
}

__END__
<opt>
  <dev name="A">
    <tables name="datatables">
      <table>a1</table>
      <table>a2</table>
      <table>a3</table>
    </tables>
    <tables name="propertytables">
      <table>A1</table>
      <table>A2</table>
    </tables>
  </dev>
  <dev name="B">
    <tables name="datatables">
      <table>b1</table>
      <table>b2</table>
    </tables>
    <tables name="propertytables">
      <table>B1</table>
      <table>B2</table>
    </tables>
  </dev>
</opt>
davorg
How to do a forcearray on a single entity? I am trying something like this: For ex, if for dev "B", if "propertytables" has a single table, it is treatedas a scalar. my $config = XMLin('./test.xml', forcearray => [ '{dev}->{B}->{tables}->{propertytables}->{table}' ]); But I guess this is a wrong way.
Abhi
Ohh I got it. I just need to specify forcearray=>[qw(table)]
Abhi