0

Here is a code sample that reproduces the behaviour I wonder about:

#!/usr/bin/perl
use strict;
use warnings;

use XML::LibXML;

my $myXMLdocument = XML::LibXML::Document->new();

my $myXML = $myXMLdocument->createElement("myXML");
$myXMLdocument->addChild($myXML);

my $element = $myXMLdocument->createElement("element");
$myXML->addChild($element);

my $node = $myXMLdocument->createElement("node");
$element->addNewChild('', $node);
$node->addNewChild('', $myXMLdocument->createAttribute( "key" => "value"));

print "$myXMLdocument->toString(2)\n";

The output :

XML::LibXML::Document=SCALAR(0x8f5a6f8)->toString(2)

I understand that this is some sort of handle for the document structure passed around by XML::LibXML.

Now why doesn't toString serialize it to human readable XML?

I may be extremely naïve about XML::LibXML; this is my first time using it instead of spewing out random XML with Bash's echo.

Borodin
  • 126,100
  • 9
  • 70
  • 144

1 Answers1

4

This is a basic Perl problem and nothing special to do with XML::LibXML. Perl expands simple variables inside quoted strings but not function calls. If you change your code to

print $myXMLdocument->toString(2), "\n";

then you will get the result you need.


Update

You are using the module slightly wrongly. These lines

my $node = $myXMLdocument->createElement("node");
$element->addNewChild('', $node);
$node->addNewChild('', $myXMLdocument->createAttribute( "key" => "value"));

create a new element $node and then call addNewChild to add it to $element. But addNewChild takes a tag name as its second parameter so Perl is stringifying the $node object to give the strange tag name that you see. Instead you need

my $node = $myXMLdocument->createElement('node');
$element->addChild($node);
$node->addChild($myXMLdocument->createAttribute(key => 'value'));

or you could stick with addNewChild and write

my $node = $element->addNewChild('', 'node');
$node->setAttribute(key => 'value');

Update

You might want to consider XML::API which is my preferred module for writing XML. It allows for concise code, and because it builds a proper XML data tree instead of just appending text to a buffer it is a lot more subtle than it may appear. For more complex structures there is a _goto method that allows you to go back to nodes in the tree and add more data.

use strict;
use warnings;

use XML::API;

my $xml = XML::API->new;
$xml->myXML_open;
$xml->element_open;
$xml->node({ key => 'value' });
$xml->element_close;
$xml->myXML_close;

print $xml;

output

<?xml version="1.0" encoding="UTF-8" ?>
<myXML>
  <element>
    <node key="value" />
  </element>
</myXML>
Borodin
  • 126,100
  • 9
  • 70
  • 144
  • Thanks - I'll read about quoting, variable & function expansion... But we are only halfway to the solution : I now get the following : ` ` This is actually what I was having from my actual script : good outer XML but unexpanded stuff inside... Another thing about expansion that I am missing ? – Jean-Marc Liotier Feb 19 '13 at 10:36
  • The problem now is that you are calling the module methods incorrectly. See the update to my answer. – Borodin Feb 19 '13 at 10:51
  • I suspected that I was confused between addChild and addNewChild but I could not put my finger on it... So this was a XML::LibXML problem after all. I am working on an Openstreetmap data import and this removed one of the last remaining hurdles. So thank you ! – Jean-Marc Liotier Feb 19 '13 at 11:00
  • The XML I'm producing is the [osmChange format](http://wiki.openstreetmap.org/wiki/OsmChange) which is produced in an utterly linear way - so the simplicity of XML:API looks good to me and I'll take advantage of my still malleable mind to give it a try before I get too used to XML::LibXML - thank you for the suggestion. For reading the XML output of Openstreetmap's Overpass API I'm using xpath expressions and they work fine. I'm excited about moving forward ! – Jean-Marc Liotier Feb 19 '13 at 11:17