Search code examples
xmlperlxml-simple

printing out a XML::SImple hash sorted by attributes


I have an XML file that looks like this :

<booklist>
   <book type="technical">
      <author>Book 1 author 1</author>
      <author>Book 1 author 2</author>
      <title>Book 1 title</title>
      <isbn>Book1ISBN</isbn>
   </book>
   <book type="fiction">
      <author>Book 2 author 1</author>
      <author>Book 2 author 2</author>
      <title>Book 2 title</title>
      <isbn>Book2ISBN</isbn>
   </book>
   <book type="technical">
      <author>Book 3 author 1</author>
      <author>Book 3 author 2</author>
      <author>Book 3 author 3</author>
      <title>Book 3 title</title>
      <isbn>Book3ISBN</isbn>
   </book>
</booklist>

I sort the XMLin by type - so the XML::Simple. I though that this would be a good way to do it. Organize each book by it type.

/tmp/walt $ cat bookparse_by_attrib.pl_dump
#!/usr/bin/perl
use strict ;
use warnings ;
use XML::Simple ;
use Data::Dumper ;
my $book = ();

my $booklist = XMLin('book.xml_with_attrib', KeyAttr => {book => 'type'});
#print Dumper($booklist);
print $booklist->{book}->{technical}->{title}  . "\n";


/tmp/walt $ ./bookparse_by_attrib.pl_dump
$VAR1 = {
          'book' => {
                    'technical' => {
                                   'author' => [
                                               'Book 3 author 1',
                                               'Book 3 author 2',
                                               'Book 3 author 3'
                                             ],
                                   'title' => 'Book 3 title',
                                   'isbn' => 'Book3ISBN'
                                 },
                    'fiction' => {
                                 'author' => [
                                             'Book 2 author 1',
                                             'Book 2 author 2'
                                           ],
                                 'title' => 'Book 2 title',
                                 'isbn' => 'Book2ISBN'
                               }
                  }
        };

this will print out :

print $booklist->{book}->{technical}->{title}  . "\n";
/tmp/walt $ ./bookparse_by_attrib.pl_dump
Book 3 title

so it works when I know the type name however this throws an error :

print $booklist->{book}->{type}->{title}  . "\n";
Use of uninitialized value in concatenation (.) or string at ./bookparse_by_attrib.pl_dump line 11.

this does not throw an error - however It does not does not print out anything.

#!/usr/bin/perl
use strict ;
use warnings ;
use XML::Simple ;
use Data::Dumper ;
my $book = ();
my $booklist = ();

foreach my $book (@{$booklist->{book}}) {
        print $book->{title} . "\n";
        }

I am trying to print out the types, and it only works out if I know the types. Ultimately, I want to type out the types and the title of book, but for now, If I could just printout the types tath would be great.


Solution

  • The structure of the key "book" is a hash reference, however you're treating it as an array reference (@{$booklist->{book}}).

    A general problem you're going to run into with the way this data is structured is that it's 100% hashes. Once you have two books of the same type, you'll only get the last book listed for each type.

    #!/usr/bin/perl
    use warnings;
    use strict;
    
    my $booklist = {
        'book' => {
            'technical' => {
                'author' => [
                    'Book 3 author 1',
                    'Book 3 author 2',
                    'Book 3 author 3'
                ],
                'title' => 'Book 3 title',
                'isbn' => 'Book3ISBN'
            },
            'fiction' => {
                'author' => [
                    'Book 2 author 1',
                    'Book 2 author 2'
                ],
                'title' => 'Book 2 title',
                'isbn' => 'Book2ISBN'
            }
        }
    };
    
    for my $book_type ( keys %{ $booklist->{book} } ) {
        printf( "Title: %s\n", $booklist->{book}->{$book_type}->{title} );
    }