Hello, I need to parse XML documents and replace the namespace prefixes, and am 
not getting quite the behavior I expect.  I am able to update the element 
prefixes, but I end up with an extra namespace definition in the root node.  I 
wasn't sure if it mattered whether the call to setAttributeNS was done before 
or after the traversal of child nodes to update element prefixes, so I tried 
making the call both before and after child traversal with no change in output.

I even tried explicitly removing the extra namespace definition that I didn't 
want, but the attribute that I want to remove isn't returned when I call 
getAttributeNode, despite appearing in the output XML.

Am I doing something incorrectly? The example code below traverses the 
DOMDocument, changing the addr: prefix to ns1.  The test document and test code 
output are also provided below.  I expected xmlns:addr to be replaced with 
xmlns:ns1, but instead I get both.

Regards,
Lara

void traverseNode( DOMNode *node )
{
    if ( !node )
    {
      std::cout << "traverseNode: NULL node" << std::endl;
      return;
    }

    std::string prefix = "ns1";

    char *name = XMLString::transcode(node->getNodeName());
    std::cout << "Traversing node " << name << std::endl;

    if (node->getPrefix() && node->getNodeType () == DOMNode::ELEMENT_NODE || 
node->getNodeType () == DOMNode::ATTRIBUTE_NODE)
    {
      std::cout << "Resetting prefix for " << name << " to " << prefix << 
std::endl;
      XMLCh *newPrefix = TranscodeFromStr((XMLByte*)prefix.c_str(), 
prefix.length(), "UTF-8").adopt();
      node->setPrefix( newPrefix );
    }


    if (node->getNodeType () == DOMNode::ELEMENT_NODE)
    {
      XMLCh *nsName = TranscodeFromStr((XMLByte*)"xmlns:addr", 9,  
"UTF-8").adopt();
      DOMAttr *oldAttr = ((DOMElement*)node)->getAttributeNode( nsName );

      if ( oldAttr )
      {
        std::string ns = std::string("xmlns:") + prefix;
        std::cout << "Resetting namespace prefix for " << nsName << " to " << 
ns << std::endl;
        XMLCh *newNs = TranscodeFromStr((XMLByte*)ns.c_str(), ns.length(), 
"UTF-8").adopt();
        ((DOMElement*)node)->setAttributeNS( XMLUni::fgXMLNSURIName, newNs, 
oldAttr->getValue() );
      }
    }

    for ( DOMNode *child = node->getFirstChild ( ); child;  child = 
child->getNextSibling ( ) )
    {
      traverseNode( child );
    }

}


int main ( int argc, char *argv[ ] )
{
  DOMDocument* doc = NULL;

    <snip, parse input XML>

  if ( doc )
  {
    DOMNode* rootNode = (DOMNode*) doc->getDocumentElement( );

    // Traverse nodes, updating prefixes
    traverseNode( rootNode );

    // Try to explicitly remove the leftover xmlns:addr attribute
    DOMNode* updatedRootNode = (DOMNode*) doc->getDocumentElement( );
    char *updatedName = XMLString::transcode(updatedRootNode->getNodeName());

    XMLCh *nsName = TranscodeFromStr((XMLByte*)"xmlns:addr", 9,  
"UTF-8").adopt();
    DOMAttr *oldAttr = ((DOMElement*)updatedRootNode)->getAttributeNode( nsName 
);
    if ( oldAttr )
    {
      std::cout << "Removing xmlns:addr from " << updatedName << std::endl;
      ((DOMElement*)updatedRootNode)->removeAttributeNode( oldAttr );
    }
    else
    {
      std::cout << "xmlns:addr not an attribute of " << updatedName << 
std::endl;
    }

    DOMLSSerializer   *theSerializer = 
((DOMImplementationLS*)impl)->createLSSerializer();
    DOMLSOutput       *theOutputDesc = 
((DOMImplementationLS*)impl)->createLSOutput();
    XMLCh*  gOutputEncoding        = 0;
    theOutputDesc->setEncoding(gOutputEncoding);

    XMLFormatTarget *myFormTarget;
    myFormTarget=new StdOutFormatTarget();
    theOutputDesc->setByteStream(myFormTarget);

    std::cout << "OUTPUT DOC:" << std::endl;
    std::cout << "--------------------------------------" << std::endl;

    // write to stdout
    theSerializer->write(doc, theOutputDesc);

    theSerializer->release();
    theOutputDesc->release();
    delete myFormTarget;
  }
}


Test document address.xml:

<?xml version="1.0"?>
<addr:address xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
    xsi:schemaLocation="http://namespaces.oreilly.com/xmlnut/address 
address-schema.xsd<http://namespaces.oreilly.com/xmlnut/address%20address-schema.xsd>"
    xmlns:addr="http://namespaces.oreilly.com/xmlnut/address";>
  <addr:fullName>
    <addr:first>Scott</addr:first>
    <addr:last>Means</addr:last>
  </addr:fullName>
</addr:address>

Test app output:

PARSING address.xml
Traversing node addr:address
Resetting prefix for addr:address to ns1
Traversing node #text
Traversing node addr:fullName
Resetting prefix for addr:fullName to ns1
Traversing node #text
Traversing node addr:first
Resetting prefix for addr:first to ns1
Traversing node #text
Traversing node #text
Traversing node addr:last
Resetting prefix for addr:last to ns1
Traversing node #text
Traversing node #text
Traversing node #text
xmlns:addr not an attribute of ns1:address
OUTPUT DOC:
--------------------------------------
<?xml version="1.0" encoding="UTF-8" standalone="no" ?><ns1:address 
xmlns:ns1="http://namespaces.oreilly.com/xmlnut/address"; 
xmlns:addr="http://namespaces.oreilly.com/xmlnut/address"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://namespaces.oreilly.com/xmlnut/address 
address-schema.xsd<http://namespaces.oreilly.com/xmlnut/address%20address-schema.xsd>">
  <ns1:fullName>
    <ns1:first>Scott</ns1:first>
    <ns1:last>Means</ns1:last>
  </ns1:fullName>
</ns1:address>





Reply via email to