Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Creating Nodes in namespace with XML::LibXML

by worik (Sexton)
on Jun 04, 2015 at 22:48 UTC ( [id://1129129]=perlquestion: print w/replies, xml ) Need Help??

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

I wish to build an XML document up node by node. The nodes will be build in functions that call functions to build child nodes and append them. Quite a straight forward way of doing XML, IMO.

All the methods I have seen to build a node that is in a namespace http://www.xml.com/pub/a/2001/11/14/xml-libxml.html?page=2 for instance need the XML::LibXML::Document. To achieve this I would need to pass a XML::LibXML::Document element around the functions or have it as a global.

What I really want is a version of XML::LibXML::Element->new(<name>, <name space>)

XML::LibXML::Element->setNamespace is not what I want as it adds namespase declarations

An example of what I am trying to do...

# Create (local) root node named $rname, the children will be $cname1 + and $cname2, $cname1 is in the same namespace as $rname and $cname2 +is in a different namespace my $node = XML::LibXML::Element->new($rname); # I want to declare the namespaces and prefixes the children will use. + NS_name1 is the namespace of the node itself but it has child nodes +that use NS_name2 $node->setNamespace(NS_name1, NS_prefix1, 1); $node->setNamespace(NS_name2, NS_prefix2, 0); # Creating the children. Thi sis not valid code, this is what I want my $cnode1 = XML::LibXML::Element->new($cname1, $NS_name1); my $cnode2 = XML::LibXML::Element->new($cname2, $NS_name2); $node->appendChild($cnode1); $node->appendChild($cnode2); return $node;

This way I need global knowledge of the name space names (and prefixes, but it would be trivial to avoid that) but I do not need to pass the complete document around as an argument or make it global

Is there some way of doing this (a two argument version of XML::LibXML::Element::new) or do I need to have the root of the tree accessible to the code making leaves/sub-trees?

Worik

Replies are listed 'Best First'.
Re: Creating Nodes in namespace with XML::LibXML
by Anonymous Monk on Jun 04, 2015 at 23:49 UTC

    Please have a look at How do I post a question effectively? - you haven't given a runnable piece of code, the expected output, and the current output.

    You seem to want to avoid passing the document object around like it's a bad thing - it's not, in fact, if I understand your question correctly, then the solution is based on that you will need to pass the XML::LibXML::Document object around and add your elements to the document as you create them, instead of handling unbound nodes.

    use warnings; use strict; use XML::LibXML; my $doc = XML::LibXML::Document->new; my $el1 = $doc->createElementNS("namespace0","aaa"); $el1->setNamespace("namespace1","p1",0); $el1->setNamespace("namespace2","p2",0); $doc->setDocumentElement($el1); my $el2 = $doc->createElement("bbb"); $el2->setNamespace("namespace2","p2",1); $el1->appendChild($el2); my $el3 = $doc->createElementNS("namespace0","ccc"); $el1->appendChild($el3); my $el4 = $doc->createElement("p1:ddd"); $el3->appendChild($el4); print $doc->toString(1); __END__ <?xml version="1.0"?> <aaa xmlns="namespace0" xmlns:p1="namespace1" xmlns:p2="namespace2"> <p2:bbb/> <ccc> <p1:ddd/> </ccc> </aaa>

    Note how the namespace declarations are automatically reused. This is actually documented in XML::LibXML::Element's setNamespace. Since you seem to want to work with XML::LibXML more closely, I strongly suggest you take the time to read all of its documentation (starting with XML::LibXML::Node, XML::LibXML::Element and XML::LibXML::Document).

      you haven't given a runnable piece of code
      True. My bad. Sorry

      That said I have worked out the XML::LibXML approach.

      For example I want to build:

      <?xml version="1.0" encoding="UTF-8"?> <O:ABC xmlns:O="ONE:" xmlns:T="two:IS:a_namEsp"> <O:ZZZ/> <T:ZZZ> <O:QWERTY> <T:UIOP/> </O:QWERTY> </T:ZZZ> </O:ABC>

      The following code does it....

      #!/usr/bin/perl -w use strict; use XML::LibXML; # NAmespaces my $ONE_ns = 'ONE:'; my $ONE_pfx = 'O'; my $TWO_ns = 'two:IS:a_namEsp'; my $TWO_pfx = 'T'; # The XML Document my $DOC = XML::LibXML->createDocument( "1.0", "UTF-8" ); # Set the root my $root = $DOC->createElement('ABC'); $DOC->setDocumentElement($root); # Establish namespaces $root->setNamespace($ONE_ns, $ONE_pfx, 1); $root->setNamespace($TWO_ns, $TWO_pfx, 0); # Build the document tree my $this = &appendOZ($root); $this = &appendTZ($this); print $DOC->toString(1); sub appendOZ { my $root = shift or die; $root->addNewChild($ONE_ns, 'ZZZ'); return $root; } sub appendTZ { my $root = shift or die; my $this = $root->addNewChild($TWO_ns, 'ZZZ'); &appendOQ($this); return $root; } sub appendOQ { my $root = shift or die; my $this = $root->addNewChild($ONE_ns, 'QWERTY'); &appendTU($this); return $root; } sub appendTU { my $root = shift or die; $root->addNewChild($TWO_ns, 'UIOP'); return $root; }

      Where a sub tree is a leaf it says:

      my $root = shift or die; $root->addNewChild(<namespace>, <name>); return $root;

      Where the sub-tree is the root of another sub-tree itself it says:

      sub appendOQ { my $root = shift or die; # Make this node my $this = $root->addNewChild(<namesace>, <name>); # Append sub tree &appendTU($this); return $root; }

      This works out nicely and does what I want. If I want a different tree:

      <?xml version="1.0" encoding="UTF-8"?> <O:ABC xmlns:O="ONE:" xmlns:T="two:IS:a_namEsp"> <O:ZZZ/> <T:ZZZ> <O:QWERTY> <T:UIOP/> </O:QWERTY> </T:ZZZ> <O:QWERTY> <T:UIOP/> </O:QWERTY> </O:ABC>

      I change the core of the programme to:

      # Build the document tree my $this = &appendOZ($root); $this = &appendTZ($this); $this = &appendOQ($this); print $DOC->toString(1);

      What I expected to be writing, when adding a sub-tree, was some thing like:

      # Make this node my $this = $root->addNewChild(<namesace>, <name>); # Append sub tree $this->append(&buildSubTree) return $this;

      The only reason (I can see, with my inexperience) to pass the root is for the namespace prefix information. It is nice to use prefixes, and I can see with hindsight that it would require some post processing of the tree to achieve that. So what I was expecting is not the "XML::LibXML" way. Fair enough

      So the answer to my question was "No, yes". Simple really

      Another thing. Some one said:

      I strongly suggest you take the time to read all of its documentation
      . Sensible advice. I have been doing exactly that. There are thousands and thousands of lines there, and they are organised as a reference not an introduction. It is hard to start the learning curve with XML::LibXML. In the absence of an introductory document there will be stupid sounding questions from beginners.

Re: Creating Nodes in namespace with XML::LibXML
by choroba (Cardinal) on Jun 05, 2015 at 10:39 UTC
    Some of the verboseness of XML::LibXML can be reduced by XML::XSH2:
    create ABC ; cd ABC ; declare-ns O ONE: ; register-namespace O ONE: ; declare-ns T two:IS:a_namEsp ; register-namespace T two:IS:a_namEsp ; set-ns ONE: O; insert element O:ZZZ into . ; my $t := insert element T:ZZZ into . ; my $q := insert element O:QWERTY into $t ; insert element T:UIOP into $q ; insert element O:QWERTY into . ; insert element T:UIOP into O:QWERTY ; # No need to create variables ev +erytime. save :f new.xml ;

    It produces almost the XML you posted in a reply, the only difference is utf is lowercase in the declaration.

    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (3)
As of 2024-04-20 01:47 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found