http://qs1969.pair.com?node_id=430355

Nitrox has asked for the wisdom of the Perl Monks concerning the following question:

I'm editing an existing XML file by cutting children and inserting elements into a twig. The orginal XML is formatted as follows:
<PrimaryServers> <Server Name="Old_1"/> <Server Name="Old_2"/> </PrimaryServers>
That particular section is edited with the following:
my $ps = $sc->first_child('PrimaryServers'); $ps->cut_children; $ps->insert_new_elt("Server")->set_att('Name', "New_1"); $ps->insert_new_elt("Server")->set_att('Name', "New_2");
Everything works as expected. However, when dumping the XML to a file with $root->print() that section appears as:
<PrimaryServers><Server Name="New_2"/><Server Name="New_1"/></PrimaryS +ervers>
How do I define a formating style on those inserted children so that the final output will appear as:
<PrimaryServers> <Server Name="New_2"/> <Server Name="New_1"/> </PrimaryServers>
I've tried setting pretty_print to 'indented' as well as the other choices but none see to work. The rest of the XML retains the original formatting, it's just the twig that I edited that is lacking the formatting.

-Nitrox

Replies are listed 'Best First'.
Re: Formatting in XML::Twig->print()
by Tanktalus (Canon) on Feb 12, 2005 at 01:10 UTC

    Just so you don't feel lonely, I remember my XML::Twig project from a couple years ago, and I'd get the odd line here and there that didn't print out pretty. Which was ok - we only wanted it pretty for visual inspection, but it didn't get in the way of the actual use of the XML file as input to another process.

    I do think that there is something funky going on in the pretty-printing of XML::Twig. That said, I'm glad that they concentrated on getting the XML parts working over the pretty-print!

Re: Formatting in XML::Twig->print()
by holli (Abbot) on Feb 12, 2005 at 06:57 UTC
    You could ask mirod, who is the author of XML::Twig. Also there is additional info at his homepage.


    holli, /regexed monk/
Re: Formatting in XML::Twig->print()
by rg0now (Chaplain) on Feb 12, 2005 at 14:12 UTC
    Why not prettifying in a post-processing step?

    I mean, if you happen to have libxml2 installed, then you have the unbeatible xmllint utility at your disposal:

    rg@something:/tmp$ echo '<PrimaryServers><Server Name="New_2"/><Server + Name="New_1"/></PrimaryServers>' | xmllint --format -
    This results in a beautiful XML layout:
    <?xml version="1.0"?> <PrimaryServers> <Server Name="New_2"/> <Server Name="New_1"/> </PrimaryServers>

    rg0now

Re: Formatting in XML::Twig->print()
by mirod (Canon) on Feb 12, 2005 at 15:19 UTC

    I can't reproduce this behaviour with the latest XML::Twig. The XML looksproperly indented. Which version are you using? If it is a recent one (3.10+), could you please post a minimal test that I could run? Thanks

    Just as a side note, you can write $ps->insert_new_elt( Server => { Name => "New_1"}); instead of $ps->insert_new_elt("Server")->set_att('Name', "New_1");.

Re: Formatting in XML::Twig->print()
by Nitrox (Chaplain) on Feb 12, 2005 at 16:26 UTC
    Mirod, I'm testing with XML::Twig v3.15 on WinXP and v3.16 on Linux, both produce the same behavior.

    Here is a minimal test stub that re-creates the formatting issue on my test machines.

    #!/bin/perl -w use strict; use XML::Twig; my $file = 'input.xml'; my $parser = new XML::Twig(KeepSpaces => 'true', ErrorContext => 2); $parser->parsefile($file); my $sc = $parser->root->first_child( q{ServerCluster[@Name="cl_app302_ +prod"]} ); my $ps = $sc->first_child('PrimaryServers'); $ps->cut_children; $ps->insert_new_elt( Server => { Name => "New_1"}); $ps->insert_new_elt( Server => { Name => "New_2"}); open(PF, "> out.xml") or die "can't open file $!\n"; $parser->root->print(\*PF);
    The input.xml file contains:
    <?xml version="1.0" encoding="ISO-8859-1"?> <Config ASDisableNagle="false" AcceptAllContent="false" IISDisableNagl +e="false" IgnoreDNSFailures="false" RefreshInterval="60" ResponseChun +kSize="64"> <Log LogLevel="Error" Name="/opt/IBMWebAS/logs/native.log"/> <VirtualHostGroup Name="foobarcom"> <VirtualHost Name="foo.bar.com"/> </VirtualHostGroup> <ServerCluster CloneSeparatorChange="false" LoadBalance="Round Robi +n" Name="cl_app302_prod" PostSizeLimit="-1" RemoveSpecialHeaders="tru +e" RetryInterval="60"> <Server CloneID="umjbf6mv" ConnectTimeout="0" ExtendedHandshake= +"false" LoadBalanceWeight="2" MaxConnections="-1" Name="swel3p_cl_app +302_prod" WaitForContinue="false"> <Transport Hostname="swel3p.bar.com" Port="8132" Protocol="ht +tp"/> </Server> <PrimaryServers> <Server Name="swel3p_sg_app302_prod"/> <Server Name="swel4p_sg_app302_prod"/> <Server Name="swel1r_sg_app302_prod"/> <Server Name="swel2r_sg_app302_prod"/> </PrimaryServers> </ServerCluster> <!-- APP URI groups point at urls --> <UriGroup Name="event/event.war_URIs"> <Uri AffinityCookie="JSESSIONID_302" Name="/event/*.jsp"/> <Uri AffinityCookie="JSESSIONID_302" Name="/event/ThreadedEven +tServlet"/> </UriGroup> <!-- Route statement bring it all together --> <Route ServerCluster="cl_app302_prod" UriGroup="event/event.war_URI +s" VirtualHostGroup="foobarcom"/> </Config>

    Which on my systems produces:

    <Config ASDisableNagle="false" AcceptAllContent="false" IISDisableNagl +e="false" IgnoreDNSFailures="false" RefreshInterval="60" ResponseChun +kSize="64"> <Log LogLevel="Error" Name="/opt/IBMWebAS/logs/native.log"/> <VirtualHostGroup Name="foobarcom"> <VirtualHost Name="foo.bar.com"/> </VirtualHostGroup> <ServerCluster CloneSeparatorChange="false" LoadBalance="Round Robi +n" Name="cl_app302_prod" PostSizeLimit="-1" RemoveSpecialHeaders="tru +e" RetryInterval="60"> <Server CloneID="umjbf6mv" ConnectTimeout="0" ExtendedHandshake= +"false" LoadBalanceWeight="2" MaxConnections="-1" Name="swel3p_cl_app +302_prod" WaitForContinue="false"> <Transport Hostname="swel3p.bar.com" Port="8132" Protocol="ht +tp"/> </Server> <PrimaryServers><Server Name="New_2"/><Server Name="New_1"/></Pr +imaryServers> </ServerCluster> <!-- APP URI groups point at urls --> <UriGroup Name="event/event.war_URIs"> <Uri AffinityCookie="JSESSIONID_302" Name="/event/*.jsp"/> <Uri AffinityCookie="JSESSIONID_302" Name="/event/ThreadedEven +tServlet"/> </UriGroup> <!-- Route statement bring it all together --> <Route ServerCluster="cl_app302_prod" UriGroup="event/event.war_URI +s" VirtualHostGroup="foobarcom"/> </Config>

    -Nitrox

      my $parser = new XML::Twig(KeepSpaces => 'true', ErrorContext => 2);

      No more mystery: KeepSpaces essentially tells XML::Twig to keep its hands off of whitespace management. So if you want your elements to be indented, you will have to do it yourself, by inserting an element containing the appropriate whitespace between the 2 Server elements. Or you could probably remove the KeepSpaces option alltogether. Is there any reason why it's there?

        Without the KeepSpaces option, XML::Twig munges all the whitespace in the original XML so that the output looks like:
        <Config ASDisableNagle="false" AcceptAllContent="false" IISDisableNagl +e="false" IgnoreDNSFailures="false" RefreshInterval="60" ResponseChun +kSize="64"><Log LogLevel="Error" Name="/opt/IBMWebAS/logs/native.log" +/><VirtualHostGroup Name="foobarcom"><VirtualHost Name="foo.bar.com"/ +></VirtualHostGroup><ServerCluster CloneSeparatorChange="false" LoadB +alance="Round Robin" Name="cl_app302_prod" PostSizeLimit="-1" RemoveS +pecialHeaders="true" RetryInterval="60"><Server CloneID="umjbf6mv" Co +nnectTimeout="0" ExtendedHandshake="false" LoadBalanceWeight="2" MaxC +onnections="-1" Name="swel3p_cl_app302_prod" WaitForContinue="false"> +<Transport Hostname="swel3p.bar.com" Port="8132" Protocol="http"/></S +erver><PrimaryServers><Server Name="New_2"/><Server Name="New_1"/></P +rimaryServers></ServerCluster> <!-- APP URI groups point at urls --> <UriGroup Name="event/event.war_URIs"><Uri AffinityCookie="JSESSIO +NID_302" Name="/event/*.jsp"/><Uri AffinityCookie="JSESSIONID_302" Na +me="/event/ThreadedEventServlet"/></UriGroup> <!-- Route statement bring it all together --> <Route ServerCluster="cl_app302_prod" UriGroup="event/event.war_URI +s" VirtualHostGroup="foobarcom"/></Config>
        -Nitrox