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

Greetings Monks. I have been wrestling with perl in xml for a couple weeks now. I have gotten to the point where I need to ask for help. Here's the situ. I'm sure there are easier solutions, but due to the constraints of the system I'm working in, I cannot download and install additional perl modules, and am stuck trying to get my xml tasks taken care of using XML::Pareser and XML::Simple.

I seem to have no trouble parsing through single xml elements. However I seem to be having trouble when it comes to the multiple elements, which are displayed as ARRAY(0...). I'm obviously missing something here and I'm ready to be schooled.

A simplified sampling of my code follows.

prod.xml:
<shelf> <product> <title>widget1</title> <cost>0.10</cost> <rating>B</rating> <color>red</color> <color>blue</color> <color>green</color> </product> <product> <title>widget2</title> <cost>0.25</cost> <rating>S</rating> <color>pink</color> <color>gray</color> <color>orange</color> </product> </shelf>
prod.pl
use XML::Simple; $file = XMLin('./prod.xml'); foreach $products (@{$file->{product}}) { print "Widget: " . $products->{title} ." \n"; print "Rating: " . $products->{rating} . "\n"; print " Cost: " . $products->{cost} . "\n"; print "Colors: " . $products->{color} . "\n\n"; }
Output
Widget: widget1 Rating: B Cost: 0.10 Colors: ARRAY(0x19c5584) Widget: widget2 Rating: S Cost: 0.25 Colors: ARRAY(0x19c55f0)

Replies are listed 'Best First'.
Re: perl xml and array issue
by fisher (Priest) on Nov 18, 2010 at 15:36 UTC
    print "Colors: " . (join ",", @{$products->{color}})."\n";
      So easy...and yet I couldn't figure this out on my own.

      This simple solution worked wonderfully!

      Thanks a ton, vroom
        look, $products->{colors} is actually a reference to an array. @{ } does dereferencing of a reference. I suggest you to spend 20 mins on perldoc perlreftut. It is small indeed.
Re: perl xml and array issue
by Anonymous Monk on Nov 18, 2010 at 15:33 UTC
Re: perl xml and array issue
by ikegami (Patriarch) on Nov 18, 2010 at 16:41 UTC
    Note that with the suggested fix, your code will fail if there's only one product or if a product has only one color. A simple fix is to configure the parser with ForceArray => [qw( product color )].
      Okay. So I've done a bit of research with ForceArray, but can't seem to make headway with this. When it comes to an item with a single entry like this:
      <product> <title>widget3</title> <cost>0.50</cost> <rating>S</rating> <color>white</color> </product>
      it returns empty. I have been poking around with my code, but can't seem to get ForceArray to return single item entries. I'm sooo close, yet sooo far...

        I don't understand the question.

        If you use ForceArray => [qw( product color )],

        foreach $products (@{$file->{product}}) { print "Widget: " . $products->{title} ." \n"; print "Rating: " . $products->{rating} . "\n"; print " Cost: " . $products->{cost} . "\n"; print "Colors: " . join(', ', @{$products->{color}})."\n\n"; }

        will work for

        <shelf> <product> <title>widget3</title> <cost>0.50</cost> <rating>S</rating> <color>white</color> </product> </shelf>

        and

        <shelf> <product> <title>widget1</title> <cost>0.10</cost> <rating>B</rating> <color>red</color> <color>blue</color> <color>green</color> </product> <product> <title>widget2</title> <cost>0.25</cost> <rating>S</rating> <color>pink</color> <color>gray</color> <color>orange</color> </product> </shelf>

        and everything in between. Without ForceArray, you'd need

        sub list { if (defined(ref($_[0])) && ref($_[0]) eq 'ARRAY') { return @{ $_[0] }; } else { return $_[0]; } } foreach $products (list($file->{product})) { print "Widget: " . $products->{title} ." \n"; print "Rating: " . $products->{rating} . "\n"; print " Cost: " . $products->{cost} . "\n"; print "Colors: " . join(', ', list($products->{color}))."\n\n"; }

        So what's the problem?

Re: perl xml and array issue
by fisher (Priest) on Nov 18, 2010 at 15:39 UTC
    or, alternatively, (and I hope more clearly to you),
    foreach $color (@{products->{color}}) { print $color." " }; print;
Re: perl xml and array issue
by locked_user sundialsvc4 (Abbot) on Nov 18, 2010 at 16:59 UTC

    As you’ll see for yourself when you read the tutorials, References are the “magic pixie dust” that lets Perl handle arbitrary data structures easily.   A reference is “a single thing” (therefore, “that lives in one place,” much like a scalar...) that refers to something else.   Vaguely like a C “pointer,” but infinitely more robust...

    One of the key notions in Perl is that of contexts.   If you refer to, say, an array-ref “in a scalar context,” you will see “a single thing” that looks like ARRAY(0..) or what-have-you.   Or maybe you get “the number of elements in the array.”   Your mileage may vary.   But anyhow, when you use an array-ref “in an array context,” you get the array of values to which it refers.   And this, basically, is what the notion of dereferencing is all about.

    First, you say “Huh?”   Then, you say “Oh, okay, now I get it ... Say, This Is Cool!!”   And so it is.

      Nit 1: A reference is not "much like a scalar", it is a type of scalar.

      Nit 2: Seeing ARRAY(0..) has nothing to do with context. An array reference is a value; it is not an operator. Context doesn't apply since it's not evaluated. Seeing ARRAY(0..) is the result of stringifying an array reference.