2

I am trying to write a Perl script that will traverse an XML file and find all entries named 'className'.

I am using a the XML::Simple library which is turning out to be very poorly named.

The library appears to represents sequences of similarly named elements as an array.

I am trying to iterate over the elements in the list, using a basic indexed loop. So I'm trying to find out how many elements are in the array:

    } elsif("ARRAY" eq ref(@_[0])) {
        my $list = @_[0];
        print "scalar($list): " . scalar($list) . "\n";
        print "\$#list: " . $#list . "\n";
        print "\n";
    }

Here is the output of my code:

scalar(ARRAY(0x600845398)): ARRAY(0x600845398)
$#list: -1

I've found references online to using the scalar function and the strange $# notation, but neither is giving me a number that makes any sense.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
spierepf
  • 2,774
  • 2
  • 30
  • 52
  • `scalar($list)` -- `$list` is already a scalar. You need to use @ to dereference $list and then use `scalar @$list` to get the length. – i alarmed alien Oct 09 '14 at 18:04
  • Also, `@_[0]` is taking a one-element array slice from `@_`. Better written as the single item `$_[0]`. – Jim Davis Oct 09 '14 at 19:55
  • Also, `$list` is a bad name for a variable that contains an array (or, as in this case, an array reference). It just encourages people to believe that arrays and lists are the same thing. – Dave Cross Oct 10 '14 at 11:24
  • I'm starting to get the feeling that the user of perl in new code should be discouraged. :) Where can I learn the meaning and necessity of all the different prefix hieroglyphics? – spierepf Oct 10 '14 at 12:33
  • Possible duplicate: *[How do I determine the number of elements in an array reference?](https://stackoverflow.com/questions/5885794/how-do-i-determine-the-number-of-elements-in-an-array-reference)* – Peter Mortensen Apr 27 '21 at 22:18
  • Just for a straight array, the search engines are fond of *[Find size of an array in Perl](https://stackoverflow.com/questions/7406807)*. – Peter Mortensen Apr 27 '21 at 22:21

2 Answers2

4

$list is an array ref, not an array. Try scalar @{$list}. Also - try XML::Twig as a way of XML parsing.

Sobrique
  • 52,974
  • 7
  • 60
  • 101
2

The use of XML::Simple in new code is discouraged.

This is from the advice of the module documentation itself:

STATUS OF THIS MODULE

The use of this module in new code is discouraged. Other modules are available which provide more straightforward and consistent interfaces. In particular, XML::LibXML is highly recommended.

The major problems with this module are the large number of options and the arbitrary ways in which these options interact - often with unexpected results.

Patches with bug fixes and documentation fixes are welcome, but new features are unlikely to be added.

For new code, I would recommend using either XML::LibXML or XML::Twig.

Both of these modules utilize XPaths for locating and modifying nodes, which is a lot more powerful than trying to translate an XML document into a perl data structure like XML::Simple does.

The following is an example of how to count the number of nodes named className in a fake XML document:

use strict;
use warnings;

use XML::LibXML;

my $xml = XML::LibXML->load_xml( IO => \*DATA );

my @className = $xml->findnodes('//className');

print "Count is " . @className . "\n";

__DATA__`
<root>
    <foo>
        <className id="one" />
        <className id="two" />
        <className id="three" />
    </foo>
    <bar>
        <className id="four" />
        <className id="five" />
        <className id="six" />
    </bar>
    <baz>
        <biz>
            <className id="seven" />
            <className id="eight" />
            <className id="nine" />
        </biz>
    </baz>
</root>

Outputs:

Count is 9
Community
  • 1
  • 1
Miller
  • 34,962
  • 4
  • 39
  • 60
  • Does findnodes only return the number of nodes that match the xpath? I can't find anything in the docs about actually traversing the document, or getting attributes from nodes. Just a cryptic reference to "In scalar context, the function will return a XML::LibXML::NamedNodeMap object." which doesn't have any documentation. – spierepf Oct 10 '14 at 12:41