0

I'm trying to build XML that looks like this using XML::Simple:

<response>
    <device>
        <interface>
            <mh>0x123abc</mh>
            <portname>Gi1/1</portname>
        </interface>
        <interface>
            <mh>0x123abc</mh>
            <portname>Gi1/1</portname>
        </interface>
        <interface>
            <mh>0x123abc</mh>
            <portname>Gi1/1</portname>
        </interface>
    </device>
</response>

I'm finding XML::Simple very difficult to behave like I want, so I tried feeding it it's own medicine:

$req = <<EOF;
<response>
    <device>
        <interface>
            <mh>0x123abc</mh>
            <portname>Gi1/1</portname>
        </interface>
        <interface>
            <mh>0x123abc</mh>
            <portname>Gi1/1</portname>
        </interface>
        <interface>
            <mh>0x123abc</mh>
            <portname>Gi1/1</portname>
        </interface>
    </device>
</response>
EOF
print Dumper(XML::Simple::XMLin($req));

yields:

$VAR1 = {
          'device' => {
                      'interface' => [
                                     {
                                       'portname' => 'Gi1/1',
                                       'mh' => '0x123abc'
                                     },
                                     {
                                       'portname' => 'Gi1/1',
                                       'mh' => '0x123abc'
                                     },
                                     {
                                       'mh' => '0x123abc',
                                       'portname' => 'Gi1/1'
                                     }
                                   ]
                    }
        };

If I feed that back into XML::Simple and print it:

my $xml = XML::Simple::XMLout($VAR1, RootName => "response");
print $xml;

I get this, which doesn't match what I sent it in the first place:

<response>
  <device>
    <interface mh="0x123abc" portname="Gi1/1" />
    <interface mh="0x123abc" portname="Gi1/1" />
    <interface mh="0x123abc" portname="Gi1/1" />
  </device>
</response>

How do I tell XML::Simple to treat a node as a node and not an attribute?

Jon A
  • 362
  • 4
  • 14

1 Answers1

4

One option is XML::Simple NoAttr

NoAttr => 1 # in+out - handy

When used with XMLout(), the generated XML will contain no attributes. All hash key/values will be represented as nested elements instead.

When used with XMLin(), any attributes in the XML will be ignored.

However, from the documentation for XML::Simple

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.

Therefore, I would strongly recommend that you use either XML::LibXML or XML::Twig because of the very problems that you're facing right now.

Trust us. This will likely be the first of many, even if this solution does work.

Community
  • 1
  • 1
Miller
  • 34,962
  • 4
  • 39
  • 60
  • NoAttr works - I'm working in a highly controlled environment, but I'll see about switching. Thank you for the warning. – Jon A Oct 01 '14 at 16:10
  • note that there's nothing *wrong* with XML::Simple - except that some of its defaults are not what many expect – ysth Oct 01 '14 at 16:17
  • 2
    Not wrong, just awful for so many reason (bad defaults being the smallest of problems). – ikegami Oct 01 '14 at 18:58
  • 1
    @ysth, there's not much wrong with the *implementation* of XML::Simple. The problem is the entire *premise* behind it: that you can losslessly (or with acceptable data loss) map between arbitrary hash/array structures and an XML infoset. – tobyink Oct 02 '14 at 12:55