in reply to LibXML setNodeName error

Several issues:

#!/usr/bin/perl use warnings; use strict; use XML::LibXML; my $xml = '<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Tr +ansform"> <xsl:element name="foo"> <xsl:value-of select="bar"/> </xsl:element> </xsl:stylesheet>'; my $dom = 'XML::LibXML'->load_xml(string => $xml) or die; my $xpc = 'XML::LibXML::XPathContext'->new($dom); for my $element ($xpc->findnodes('//xsl:element')) { my ($name_attr) = $xpc->findnodes('@name', $element); $element->removeAttribute('name'); $element->setNodeName($name_attr->getValue); } print $dom;
($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

Replies are listed 'Best First'.
Re^2: LibXML setNodeName error
by geddie2001 (Novice) on Jun 26, 2017 at 16:42 UTC
    This is close. The output is:
    <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" versi +on="1.0"> <xsl:foo> <xsl:value-of select="bar"/> </xsl:foo> </xsl:stylesheet>
    but what I was asking for was:
    <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" versi +on="1.0"> <foo> <xsl:value-of select="bar"/> </foo> </xsl:stylesheet>
    Everything you have done so far is great, thank you. If you can help me with this last piece, it will be perfect. I'm sorry for my ignorance. I have a lot to learn when it comes to Perl.

      I remember doing battle with XML::LibXML in a similar situation a few years ago. IIRC, what I found back then is that the problem is namespaces - note how the document originally has only one namespace (http://www.w3.org/1999/XSL/Transform) with only one namespace prefix (xsl). What you're asking to do is move the node into a completely different namespace, specifically in this case the default one. I remember not being able to find the appropriate combinations of API calls to achieve this so that the resulting XML looked clean, and playing around by adding $element->setNamespace(...); to choroba's code seems to confirm this, the best I can do so far is <foo xmlns="...">. It seemed that once a node has been created in a namespace, it's stuck there you can't get it back into the default namespace cleanly. Back then I ended up writing a routine to create a new node in the new namespace. Now since this was a while ago, it's possible I missed the appropriate API function, but even now going through the XML::LibXML docs and Googling a bit I still don't see an obvious way.

      <update2> Caveat: The below will completely ignore any other attributes in the element being replaced, so for example if you've got <xsl:element namespace=... or use-attribute-sets, that will be ignored and lost! </update2>

      Here's what my workaround would look like (based in part on choroba's code):

      use warnings; use strict; use XML::LibXML; my $xml = <<'END_XML'; <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Tr +ansform"> <xsl:element name="foo"> <xsl:value-of select="bar"/> </xsl:element> </xsl:stylesheet> END_XML my $doc = XML::LibXML->load_xml(string => $xml) or die; my $xpc = XML::LibXML::XPathContext->new($doc); for my $el ($xpc->findnodes('//xsl:element')) { my $newel = $doc->createElement($el->getAttribute('name')); $newel->appendChild($_) for $el->childNodes; $el->replaceNode($newel); } print $doc; __END__ <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" versi +on="1.0"> <foo> <xsl:value-of select="bar"/> </foo> </xsl:stylesheet>

      Update: Made description more accurate.

        Thank you wise Perl Monks! This is terrific. I was starting to write numerous sub routines and it just looked rubbish. I appreciate all your help. Is there anything I need to do to mark this question as answered?
        I've noticed a new issue. If the value of the name attribute contains the character "{" then I receive the error:
        bad name at replaceelementname.pl line 8.
        There may be other characters that causes this error as well. Any help would be appreciated. If I have to drop XML::LibXML completely, that is okay.
        Create a new node, in the default namespace, and completely replace the existing element with it.