0

I have many multi-node XML files that I'm parsing with XML::Simple. So far it works great. One of the first things I do is get the length of the XML file (node count) using this:

my $xmltemp = XML::Simple->new(
    SuppressEmpty => 1
);

my $product = $xmltemp->XMLin('xml/' . $basename . '.xml');

my $qfr = @{ $product->{$basename}};
print "$qfr = qfr\n";

The variable $basename is provided by looping through an array of file names. The nodename and filename are the same.

This works in all the files, except for files that only have one node. The program tanks at the attempt to create the $qfr variable.

If I edit one of the single-node XML files and create another node (dupe the existing one) and rerun, this works fine.

What is wrong that causes a one node XML to not respond to a simple scalar variable assignment?

The print line won't even execute.

NOTE: I cut and pasted the important bits of code from a .pl and and .pm to make it easy to grasp.

EDIT: Here is a single node XML sample:

<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<FUNDDATA>
  <FUND_DATA>
    <ADVISOR_FUND_CUSIP>316146703</ADVISOR_FUND_CUSIP>
    <ADVISOR_FUND_ID>01118</ADVISOR_FUND_ID>
    <ADVISOR_FUND_NAME>Pizza Fund - Class A</ADVISOR_FUND_NAME>
    <ADVISOR_FUND_SASID>01118</ADVISOR_FUND_SASID>
    <ALL_ADVISOR_CLASSES>01118,01123,01124,01125,01126</ALL_ADVISOR_CLASSES>
    <ALL_ADVISOR_CLASSES_CUSIPS>316146703,316146885,316146877,316146802,316146869</ALL_ADVISOR_CLASSES_CUSIPS>
    <ALL_ADVISOR_CLASSES_SASIDS>01118,01123,01124,01125,01126</ALL_ADVISOR_CLASSES_SASIDS>
    <ALL_ADVISOR_CLASSES_TYPES>A,B,C,T,I</ALL_ADVISOR_CLASSES_TYPES>
    <ALL_RETAIL_CLASSES>00026</ALL_RETAIL_CLASSES>
    <ALL_RETAIL_CLASSES_CUSIPS>316146109</ALL_RETAIL_CLASSES_CUSIPS>
    <ALL_RETAIL_CLASSES_SASIDS>00026</ALL_RETAIL_CLASSES_SASIDS>
    <ALL_RETAIL_CLASSES_TYPES>N</ALL_RETAIL_CLASSES_TYPES>
    <BUSINESS_UNIT>CCC</BUSINESS_UNIT>
    <DATE_ID>September 2000</DATE_ID>
    <PRIMARY_FUND_ID>000044</PRIMARY_FUND_ID>
    <RETAIL_FUND_CUSIP>44444</RETAIL_FUND_CUSIP>
    <RETAIL_FUND_ID>00026</RETAIL_FUND_ID>
    <RETAIL_FUND_NAME>Pizza Fund</RETAIL_FUND_NAME>
    <RETAIL_FUND_SASID>00026</RETAIL_FUND_SASID>
    <TRADE_SYMBOL>CCHCC</TRADE_SYMBOL>
  </FUND_DATA>
</FUNDDATA>
Borodin
  • 126,100
  • 9
  • 70
  • 144
dbonneville
  • 2,079
  • 4
  • 19
  • 26
  • Post an example of your XML as well. – nwk Jan 12 '15 at 17:11
  • @ nwk, I edited the post to include sample XML. Thanks. – dbonneville Jan 12 '15 at 17:15
  • 1
    If you weren't aware, please note that [the documentation for `XML::Simple`](https://metacpan.org/module/XML::Simple) says, *"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."* It misrepresents the XML structure in several ways, and an `XMLin` followed by `XMLout` will rarely reproduce the original. – Borodin Jan 12 '15 at 17:29
  • I know XML::Simple is not recommended. I was required to use it. I also found this thread which seems to be the issue and offer a solution: http://stackoverflow.com/questions/14841464/not-an-array-reference-when-using-perls-xmlsimple – dbonneville Jan 12 '15 at 17:39
  • Unrelated to your problem, `$xmltemp` is a particularly poor identifier for a variable. All variables are more or less temporary, and involving `temp` in their names just creates noise. – Borodin Jan 12 '15 at 17:40
  • 1
    @dbonneville: Okay, a procedural requirement is hard to argue with. But if you are in a position to register your disapproval then I suggest you do so. The choice has already cost your time and ours because of the often arcane behaviour of the module. There is no doubt that it will cost very much more in the future. – Borodin Jan 12 '15 at 17:43
  • If you can argue the toss, point out that `XML::Twig` is way nicer and generally produces better code. – Sobrique Jan 12 '15 at 17:47
  • 1
    @Sobrique: There are several very good Perl XML modules. `XML::Simple` has gained traction mainly through its namespace, although a better title could be `XML::Naive`. Personally, I alternate between [`XML::LibXML`](https://metacpan.org/module/XML::LibXML) and [`XML::Twig`](https://metacpan.org/module/XML::Twig) with a preference for the former. [`XML::Smart`](https://metacpan.org/module/XML::Smart) is also pretty good, and there are many more. – Borodin Jan 12 '15 at 17:53

1 Answers1

1

This is just one of the nasties that you may find when using XML::Simple.

In this case there is a solution: You need to enable the ForceArray option in the constructor call, like so

my $xmltemp = XML::Simple->new(
    SuppressEmpty => 1,
    ForceArray    => 1,
);

The documentation has this to say about it

This option should be set to '1' to force nested elements to be represented as arrays even when there is only one.

Borodin
  • 126,100
  • 9
  • 70
  • 144