Search code examples
perlxml-serializationxml-simple

How do I specify that an XML::Simple data point is a node and not an attribute?


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?


Solution

  • 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.