Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Add attribute to xml with XML::LibXML

by Yshyeeni (Initiate)
on Jul 30, 2013 at 13:43 UTC ( #1047029=perlquestion: print w/ replies, xml ) Need Help??
Yshyeeni has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to add an attribute to existing XML, using XML::LibXML.

<arbre> <branche name="courbe" > <description> <![CDATA[une belle branche]]> </description> <feuilles> <fleur color="blue" order="1" /> <fleur color="white" order="2" /> <fleur color="yellow" order="3" /> </feuilles> </branche> <branche name="droite" > <description> <![CDATA[une branche commune]]> </description> <feuilles> <fleur color="purple" order="1" /> <fleur color="green" order="2" /> </feuilles> </branche> </arbre>

That I am trying to transform into :

<arbre> <branche name="courbe" type="conifere"> <description> <![CDATA[une belle branche]]> </description> <feuilles> <fleur color="blue" order="1" /> <fleur color="white" order="2" /> <fleur color="yellow" order="3" /> </feuilles> </branche> <branche name="droite" type="resineux"> <description> <![CDATA[une branche commune]]> </description> <feuilles> <fleur color="purple" order="1" /> <fleur color="green" order="2" /> </feuilles> </branche> </arbre>

Notice the type attribute in branche tag.
So far I have the following :

#!/usr/bin/env perl -w use strict; use XML::LibXML; $parser = XML::LibXML->new(); $dom = $parser->load_xml(); # now I do what? exit 0;

I know how to do this with XML::Simple, but someone told me that the use of this librairie is not recommended.
Which might be true because I have encodings and stripped CDATA problems

From what I understand from the documentation $dom is a document object which has a method called createAttribute that I might be able to use.
Any solution?.
Thanks

Comment on Add attribute to xml with XML::LibXML
Select or Download Code
Re: Add attribute to xml with XML::LibXML
by daxim (Chaplain) on Jul 30, 2013 at 13:49 UTC

      Yes, but my question was answered and editing it seemed an ugly choice.

Re: Add attribute to xml with XML::LibXML
by Loops (Hermit) on Jul 30, 2013 at 14:11 UTC

    Create an iterator, pass over each element looking for 'branche' nodes, and update them when found:

    use strict; use warnings; use XML::LibXML; use XML::LibXML::Iterator; my $parser = XML::LibXML->new(); my $dom = $parser->load_xml(location => 'input.xml'); my %newtypes = ( courbe => 'conifere', droite => 'resineux' ); my $iter = XML::LibXML::Iterator->new( $dom->documentElement ); while ( $iter->nextNode() ) { my $node = $iter->current(); next unless $node->nodeName eq 'branche'; $node->setAttribute( 'type', $newtypes{$node->getAttribute('name')} ); } print $dom->toString; exit 0;
    produces:
    <?xml version="1.0"?> <arbre> <branche name="courbe" type="conifere"> <description> <![CDATA[une belle branche]]> </description> <feuilles> <fleur color="blue" order="1"/> <fleur color="white" order="2"/> <fleur color="yellow" order="3"/> </feuilles> </branche> <branche name="droite" type="resineux"> <description> <![CDATA[une branche commune]]> </description> <feuilles> <fleur color="purple" order="1"/> <fleur color="green" order="2"/> </feuilles> </branche> </arbre>

      FYI, if your version of XML::LibXML is vaguely recent (since 1.9x), then this:

      $node->setAttribute( 'type', $newtypes{$node->getAttribute('name')} );

      Can be written as:

      $node->{type} = $newtypes{ $node->{name} };

      That is, XML::LibXML::Element acts like a hashref, and you can get/set attributes that way.

      package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name
Re: Add attribute to xml with XML::LibXML
by ikegami (Pope) on Jul 31, 2013 at 01:35 UTC
    Or using XPaths:
    use strict; use warnings; use XML::LibXML; my $parser = XML::LibXML->new(); my $doc = $parser->load_xml(location => 'input.xml'); my %types = ( courbe => 'conifere', droite => 'resineux' ); for my $branch_node ($doc->findnodes('/arbre/branche')) { $branch_node->setAttribute(type => $types{$branch_node->getAttribu +te('name')}); } print $doc->toString;
Re: Add attribute to xml with XML::LibXML
by Yshyeeni (Initiate) on Jul 31, 2013 at 13:24 UTC

    Hi,
    Thanks for your help.
    For your information (or future readers), I had to take two xml files, add attributes to them xml and join them.

    For example :

    File1 had:

    <?xml version="1.0" encoding="UTF-8"?> <arbre> <branche name="courbe" > <description> <![CDATA[une belle branche]]> </description> <feuilles> <fleur color="blue" order="1" /> <fleur color="white" order="2" /> <fleur color="yellow" order="3" /> </feuilles> </branche> <!--etc...--> </arbre>

    File2 had :

    <?xml version="1.0" encoding="UTF-8"?> <arbre> <branche name="droite" > <description> <![CDATA[une branche commune]]> </description> <feuilles> <fleur color="purple" order="1" /> <fleur color="green" order="2" /> </feuilles> </branche> <!--etc...--> </arbre>

    And the expected result was

    <arbre> <branche name="courbe" type="conifere"> <description> <![CDATA[une belle branche]]> </description> <feuilles> <fleur color="blue" order="1" /> <fleur color="white" order="2" /> <fleur color="yellow" order="3" /> </feuilles> </branche> <!--etc...--> <branche name="droite" type="resineux"> <description> <![CDATA[une branche commune]]> </description> <feuilles> <fleur color="purple" order="1" /> <fleur color="green" order="2" /> </feuilles> </branche> <!--etc...--> </arbre>

    Here is the code :

    sub _mergeXML { my $FILE1 = shift; my $FILE2 = shift; my $FILEOUT = shift; my $parser = XML::LibXML->new(); my @wanted; my $genericDom = $parser->load_xml(location => $FILE1); for my $branch_node ($genericDom->findnodes("/arbre/branche")) { $branch_node->setAttribute(type => "conifere"); } push(@wanted, $genericDom->documentElement->findnodes("./*")); my $customDom = $parser->load_xml(location => $FILE2); for my $branch_node ($customDom->findnodes("/arbre/branche")) { $branch_node->setAttribute(type => "resineux"); } push(@wanted, $customDom->documentElement->findnodes("./*")); my $new = XML::LibXML::Document->new( '1.0', 'UTF-8' ); $new->addChild($new->createComment("So, in the end we have a fores +t...")); my $root = XML::LibXML::Element->new( 'arbre' ); $new->addChild( $root ); $root->addChild( $_ ) for @wanted; my $pp = XML::LibXML::PrettyPrint->new(indent_string => " "); $pp->pretty_print($new); open(FILE,">$FILEOUT") or die $!; print FILE $new->toString;close +FILE; }

    Cheers

      Nop... Nothing to say.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1047029]
Approved by Loops
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others about the Monastery: (10)
As of 2014-07-11 03:31 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    When choosing user names for websites, I prefer to use:








    Results (217 votes), past polls