Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?

Problem to add xml element in a formatted structure

by gdanenb (Acolyte)
on Feb 09, 2012 at 09:07 UTC ( #952674=perlquestion: print w/replies, xml ) Need Help??
gdanenb has asked for the wisdom of the Perl Monks concerning the following question:

For some reason when I append element to xml file, it's written in one line, i.e. not formatted

Original xml:

<configuration> <property> <name>test1</name> </property> </configuration>
And the code is:
my $parser =XML::LibXML->new(); my $doc =$parser->parse_file($file) or die $!; my $root =$doc->getDocumentElement; my $searchPath="/configuration"; my ($val)=$root->findnodes($searchPath); my $propTag=$doc->createElement("property"); $val->appendChild($propTag); my $nameTag=$doc->createElement("name"); $nameTag->appendTextNode($name); $propTag->appendChild($nameTag); $doc->setDocumentElement($root); $doc->toFile($file,1);
Which resulted with:
<configuration> <property> <name>test1</name> </property> <property><name>test2</name></property></configuration>
instead of:
<configuration> <property> <name>test1</name> </property> <property> <name>test2</name> </property> </configuration>

Replies are listed 'Best First'.
Re: Problem to add xml element in a formatted structure
by tobyink (Abbot) on Feb 09, 2012 at 11:06 UTC

    In general, whitespace in XML is considered significant. OK, in many dialects of XML nobody cares about whitespace, but because it does matter in some XML dialects, general XML tools (such as XML::LibXML) will not insert whitespace for you.

    Firstly, you should ask yourself, do you care about indenting and pretty formatting the XML? I agree that it's nice to have, but do you want it at the cost of potentially complicating and slowing down your code?

    In some cases the answer to this is no. If the XML is only ever going to be processed by scripts, then it doesn't matter what it looks like, as long as it works.

    In other cases, you know that the XML you're generating is likely to be read and edited by humans with text editors. So slowing your code down and complicating it might be worth the pay-off.

    If you decide that you don't care about whitespace, then you're done. Your code is working fine.

    If you do care about whitespace, you've got two alternative solutions:

    • Include a bunch of $tag->appendTextNode("\n     "); sort of things sprinkled in your code to ensure that all the linebreaks and whitespace you want get generated. Or;
    • Generate your XML as you are doing it now, and then post-process it using an existing XML formatting tool.

    The first option will keep your code running roughly at the current speed, but litters your code with junk that is likely to make it less maintainable.

    The second option is likely to slow down your script somewhat (though with small files like the one you give as an example, negligibly) but doesn't clutter your code as much.

    One module that can prettify your XML is XML::LibXML::PrettyPrint. There are others, but I personally think it's the best of the bunch. (Though I did write it, so I would!) Here's how you'd change your code to use it... Replace this:


    With this:

    require XML::LibXML::PrettyPrint; XML::LibXML::PrettyPrint -> new( element => {inline=>['name']} ) -> pretty_print($doc) -> toFile($file);

    Setting name as an inline element ensures that your output is formatted like this:

    <configuration> <property> <name>test1</name> </property> <property> <name>test2</name> </property> </configuration>

    The default (without making any elements inline) would have been like this:

    <configuration> <property> <name> test1 </name> </property> <property> <name> test2 </name> </property> </configuration>

    Using the defaults allows you to simplify your code even more though:

    require XML::LibXML::PrettyPrint; XML::LibXML::PrettyPrint->pretty_print($doc)->toFile($file);

      In my case human readable format is important
      Additional module is problematic as well. since this is on running site

      I don't understand why creating a new document with
      $doc->toString(1) or $doc-toFile($f,1)
      is working fine
      Only when appending elements the problem appear... I used xmllint --format to format xml structure but it's not pure perl way...

        So you are able to modify the code on a running site, but not add a module to implement your need on a running site? What if you were to modify your code by cutting and pasting the code from the module?

        Just trying to understand where that line is drawn, and possibly getting you to evaluate why.


Re: Problem to add xml element in a formatted structure
by choroba (Chancellor) on Feb 09, 2012 at 12:49 UTC
    Crossposted at StackOverflow. It is considered polite to inform about crossposting so people do not waste their time on finding solutions someone else has already found in the other site.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://952674]
Approved by marto
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (6)
As of 2017-06-24 03:48 GMT
Find Nodes?
    Voting Booth?
    How many monitors do you use while coding?

    Results (556 votes). Check out past polls.