Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery

Comment on

( #3333=superdoc: print w/replies, xml ) Need Help??

What follows began life as a response to an email enquiry perhaps others might find it useful ...

Hi Jack*

Thanks for your email - I hope I can help you solve your problem while you still have some hair left.

I'd like to start with two observations:

  1. Your confusion is really nothing to do with XML::Simple. You simply aren't completely comfortable with Perl's references yet. Once you've got anonymous data structures and nested hashes "off pat" you'll find that the output of Data::Dumper starts to make sense and you'll find applications in all your Perl code, not just when you're working with XML.

    Mark Jason Dominus has written a quick tutorial on Perl references. It's already installed on your hard disk but you can read it online here. (Also, busunsl has written a tutorial here).

  2. You asked for help transforming this XML:

    <opt> <trans> <idnumber1 status="not contacted" assignee="jack" /> </trans> </opt>

    To this:

    <opt> <trans> <idnumber1 status="not contacted" assignee="jack" /> <idnumber2 status="contacted" assignee="jill" /> </trans> </opt>

    I'm not going to help you do that because (and I'm going to try to break this to you gently ... ) that would be just plain dumb!

In XML, 'things' that are of the same type should be represented using the same tags. Using <idnumber1> for the first thing and <idnumber2> for the seconds is, well, dumb. Instead, since I'm not sure what these 'things' are, I'm going to use <item> - I'd encourage you to use a tag which more accurately describes what they are.

So what I am going to do is show you how to transform this:

<opt> <trans> <item id="1" status="not contacted" assignee="jack" /> </trans> </opt>

To this:

<opt> <trans> <item id="1" status="not contacted" assignee="jack" /> <item id="2" status="contacted" assignee="jill" /> </trans> </opt>

Please bear in mind that XML::Simple does not care about the order of attributes - and you shouldn't either.

As a special bonus (since I have not been very kind about your stated goals and since you asked so nicely) I'm going to show you two ways to do it.

The first sample script reads the XML into $opt:

my $xs = XML::Simple->new( forcearray => [ 'item' ], keyattr => { item => 'id' }, rootname => 'opt', ); my $opt = $xs->XMLin(\*DATA);

(I use the convention of re-using the outermost tag name as the variable name but it is just a convention). I have explicitly enabled array folding, so you can refer to the first (and in fact only) 'item' as:


The {item}->{1} syntax can be read as "the <item> element which has an 'id' attribute with a value of '1'". I'm assuming you want to add another element with an id of '2' and that you somehow know that id number 2 has not already been used. So to add an element, we simply create a hashref with the relevant attributes (key => value pairs) and store it in the <item> with id '2':

$opt->{trans}->{item}->{2} = { status => 'contacted', assignee => 'j +ill' };

This is pretty simple (once you know how) but it has a couple of drawbacks. First, as I mentioned, you need to know which id's are free. Second, since array folding is enabled, the <item>'s are stored in a hash, so the order of the elements from XMLout is not guaranteed to match the original order. Anyway, here's a complete script:

#!/usr/bin/perl -w use strict; use XML::Simple; my $xs = XML::Simple->new( forcearray => [ 'item' ], keyattr => { item => 'id' }, rootname => 'opt', ); my $opt = $xs->XMLin(\*DATA); $opt->{trans}->{item}->{2} = { status => 'contacted', assignee => 'jil +l' }; print $xs->XMLout($opt); __DATA__ <opt> <trans> <item id="1" status="not contacted" assignee="jack" /> </trans> </opt>

The second script does not suffer from either of those drawbacks. It disables array folding by setting keyattr => {}. This means the <item>'s are stored in an array rather than a hash (so order is preserved) and the first item is referred to as:


(Note the square brackets meaning an array and the first element in an array is at position 0). The whole list of items is:

@{ $opt->{trans}->{item} }

So we can work out a unique ID based on how many items there are (not foolproof but useful for an example) and 'push' another one onto the end of the list like this:

my $id = @{ $opt->{trans}->{item} } + 1; push @{ $opt->{trans}->{item} }, { id => $id, status => 'contacted', + assignee => 'jill' };

Here's the complete script:

#!/usr/bin/perl -w use strict; use XML::Simple; my $xs = XML::Simple->new( forcearray => [ 'item' ], keyattr => { }, rootname => 'opt', ); my $opt = $xs->XMLin(\*DATA); my $id = @{ $opt->{trans}->{item} } + 1; push @{ $opt->{trans}->{item} }, { id => $id, status => 'contacted', a +ssignee => 'jill' }; print $xs->XMLout($opt); __DATA__ <opt> <trans> <item id="1" status="not contacted" assignee="jack" /> </trans> </opt>

For more info on array folding and the keyattr and forcearray options, you might like to look at this article.

Good luck.


* names changed to protect the innocent

In reply to Adding elements using XML::Simple by grantm

Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":

  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.
  • Log In?

    What's my password?
    Create A New User
    and all is quiet...

    How do I use this? | Other CB clients
    Other Users?
    Others perusing the Monastery: (7)
    As of 2018-06-22 21:52 GMT
    Find Nodes?
      Voting Booth?
      Should cpanminus be part of the standard Perl release?

      Results (124 votes). Check out past polls.