tags:

views:

402

answers:

4

How can I take a Perl array like this

@categories = ( ["Technology", "Gadgets"], ["TV & Film"] );

and generate this XML snippet?

<itunes:category text="Technology">
    <itunes:category text="Gadgets"/>
</itunes:category>
<itunes:category text="TV &amp; Film"/>

I can change the array if there's an easier way to get to the same output.

+1  A: 

For a general approach of generating XML with perl have a look at XML::Generator or XML::Writer.

Inshallah
Any particular reason for the downvote?
Inshallah
Wasn't me, but probably for dealing with XML as text rather than via one of the many, many modules that won't generate bad XML.
David Toso
I did make two suggestions (XML::Generator and XML::Writer) although I'm not sure whether and how much checking they do. And as for generating bad XML, the code in my answer will *not* generate bad XML **for this particular input** :-).
Inshallah
Well, now it will not (added `<xml>` tags) :-).
Inshallah
Indeed. I've found that (modern) Perl programmers are very idiomatic about the way they deal with common programming questions. For example, you'd often get a hostile reaction to even the suggestion of using regexen to parse HTML, rather than using one of the compliant parser modules.
David Toso
I kind of can understand that. Providing the code in my answer may solve the OP's immidiate need, but doesn't educate him. It's not really very useful. The OP may not be a programmer and may just be trying to get something done without really trying to learn anything new (no offence to this OP in particular); in that case the code will help him, and he may even comment with a thank you; to me that is sufficient reason to post this code.
Inshallah
On the other hand, now that I think of it, my highest voted answer was one that was very specific, and didn't educate. Why was that voted so high? Maybe I should delete it (may earn a badge :-).
Inshallah
I work with perl so infrequently, I always wind up having to relearn arrays. It gets very frustrating when I get errors on some basic syntax, but I can never seem to find examples similar to what I need (or at least what I think I need). I understand why generating XML this way is a bad idea and I wouldn't normally do it like this. I do thank you -- the code works, but I'm still having trouble with the rest of my script.
JustinStolle
@JustinStolle: "I do thank you ..." my god, how I love to hear those words :-). You are most welcome.
Inshallah
+1  A: 

For starters, I would definately change the array. (There is no obvious mapping between the data and your desired XML fragment.)

Something like the following POO representation?

my $categories = { 
    "Technology" => {
        "Gadgets" => undef
    }, 
    "TV & Film" => undef
};
David Toso
+4  A: 

I actually think XML::Simple is one of the easiest xml modules to use depending on what you need.

The snippet you reference above though is not actually valid xml not having a root tag. Do you want to generate the snippet or a full valid xml document?

XML::Generator is another good one. Neither of those will generate the snippet you have there though since they will include a root tag.

Given your motivation for the question in your comment below you might want to look at: Mac::Itunes::Library::XML

And as a general corollary: Most of the time when dealing with perl search.cpan.org will find you what you need and http://cpanratings.perl.org/ will show you how well recieved something is by the community if the there are a lot of options.

Jeremy Wall
I'm just looking for the snippet at this point. But the overall goal of the code is to generate a full XML document that looks like: http://www.apple.com/itunes/whatson/podcasts/specs.html#exampleI'm getting a list of MP3 files from a directory, reading the date and file size as well as values from the ID3 tags. So if anyone has a better solution for that, I'm all ears.
JustinStolle
The Mac::iTunes stuff is really old and probably doesn't work anymore. The last version of iTunes it tried to handle was version 4.
brian d foy
+2  A: 

I don't know why Inshalla answer has been downvoted because XML::Generator & XML::Writer are both good modules for writing out XML.

Using the Whats on iTunes? spec you commented on then this is how it could look using XML::Generator:

use strict;
use warnings;
use XML::Generator;

my $x = XML::Generator->new( pretty => 2, conformance => 'strict' );

my $itunes_ns = [ 'itunes' => 'http://www.itunes.com/dtds/podcast-1.0.dtd' ];

say $x->xmldecl( encoding => 'UTF-8' );
say $x->rss( 
    $x->channel(
        $x->title('All about Everything'),

        $x->category( $itunes_ns, { text => 'Technology' }, 
            $x->category( $itunes_ns, { text => 'Gadgets' } ),
        ),

        $x->category( $itunes_ns, { text => 'TV & Film' } ),
    ),
);


This produces:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<rss xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"&gt;
  <channel>
    <title>All about Everything</title>
    <itunes:category text="Technology">
      <itunes:category text="Gadgets" />
    </itunes:category>
    <itunes:category text="TV & Film" />
  </channel>
</rss>


To answer the "turn perl array into XML" then here is one example:

use strict;
use warnings;
use XML::Generator;

my $x = XML::Generator->new( pretty => 2, conformance => 'strict' );

my $itunes_ns = [ 'itunes' => 'http://www.itunes.com/dtds/podcast-1.0.dtd' ];

my @categories = ( { "Technology" => [ "Gadgets", 'Gizmo' ] }, "TV & Film" );

say $x->xmldecl( encoding => 'UTF-8' );
say $x->rss( 
    $x->channel(
        $x->title('All about Everything'),

        map { recurse( $_ ) } @categories,
    ),
);

sub recurse {
    my $item = shift;
    return $x->category( $itunes_ns, { text => $item } ) 
        unless ref $item eq 'HASH';

    my ($k, $v) = each %$item;
    return $x->category( $itunes_ns, 
                         { text => $k }, 
                         map { recurse ( $_ ) } @$v );
}


Look at this previous SO question something a bit similar

/I3az/

draegtun