5

What I tried and what doesn't work:

  • Input:

    $d = new DOMDocument();
    $d->formatOutput = true;
    
    // Out of my control:
    $someEl = $d->createElementNS('http://example.com/a', 'a:some');
    
    // Under my control:
    $envelopeEl = $d->createElementNS('http://example.com/default',
                                      'envelope');
    $d->appendChild($envelopeEl);
    $envelopeEl->appendChild($someEl);
    
    echo $d->saveXML();
    
    $someEl->prefix = null;
    echo $d->saveXML();
    
  • Output is invalid XML after substitution:

    <?xml version="1.0"?>
    <envelope xmlns="http://example.com/default">
      <a:some xmlns:a="http://example.com/a"/>
    </envelope>
    <?xml version="1.0"?>
    <envelope xmlns="http://example.com/default">
      <:some xmlns:a="http://example.com/a" xmlns:="http://example.com/a"/>
    </envelope>
    

Note that <a:some> may have children. One solution would be to create a new <some>, and copy all children from <a:some> to <some>. Is that the way to go?

5
  • It is easier if you use a converter xml to array and backwards minimal reproducible example[1] [1]: stackoverflow.com/questions/1397036/… Commented Feb 22, 2013 at 17:21
  • @AURIGADL Easier for the CPU or for the programmer? :) Commented Feb 22, 2013 at 17:22
  • 1
    I just realized that changing the namespace of a node (here: from a to default) is the same as renaming the node. So this question can be marked as a duplicate of the question "Rename an XML node using PHP", which already has a decent answer. Commented Feb 22, 2013 at 23:30
  • I now found a robust solution which may be worthy an answer, despite the fact that moving to default namespace is akin to renaming. Commented Feb 26, 2013 at 15:19
  • The aforementioned solution is simply to create a wrapper for the rename function from my answer to that other question: function moveToDefaultNamespace($element) { renameElement($element, $element->localName); } Commented Feb 26, 2013 at 16:18

1 Answer 1

3

This is really an interesting question. My first intention was to clone the <a:some> node, remove the xmlns:a attribute, remove the <a:some> and insert the clone - <a>. But this will not work, as PHP does not allow to remove the xmlns:a attribute like any regular attribute.

After some struggling with DOM methods of PHP I started to google the problem. I found this comment in the PHP documentation on this. The user suggest to write a function that clones the node manually without it's namespace:

<?php

/**
 * This function is based on a comment to the PHP documentation.
 * See: http://www.php.net/manual/de/domnode.clonenode.php#90559
 */
function cloneNode($node, $doc){
  $unprefixedName = preg_replace('/.*:/', '', $node->nodeName);
  $nd = $doc->createElement($unprefixedName);

  foreach ($node->attributes as $value)
    $nd->setAttribute($value->nodeName, $value->value);

  if (!$node->childNodes)
    return $nd;

  foreach($node->childNodes as $child) {
    if($child->nodeName == "#text")
      $nd->appendChild($doc->createTextNode($child->nodeValue));
    else
      $nd->appendChild(cloneNode($child, $doc));
  }

  return $nd;
}

Using it would lead to a code like this:

$xml = '<?xml version="1.0"?>
<envelope xmlns="http://example.com/default">
  <a:some xmlns:a="http://example.com/a"/>
</envelope>';

$doc = new DOMDocument();
$doc->loadXML($xml);

$elements = $doc->getElementsByTagNameNS('http://example.com/a', 'some');
$original = $elements->item(0);

$clone = cloneNode($original, $doc);
$doc->documentElement->replaceChild($clone, $original);

$doc->formatOutput = TRUE;
echo $doc->saveXML();
Sign up to request clarification or add additional context in comments.

14 Comments

Thanks! I edited your code a little bit, mainly fixed syntax, and added the cloneNode definition from the comment that you linked to. In the end this is actually what I proposed in my question (copy all children), but of course it's nice to have a ready-made function.
Fine. I just didn't wanted to reproduce the code from the comment and also wanted to keep the code as short as possible
Had to tweak the function somewhat. I noticed, it doesn't remove the namespace prefix, i.e. in the original form it preserves <a:some>, while I want plain <some>.
Please don't edit too much. My answer - as is - worked as you expected. I have tested it
I've tested it too: There were syntax errors. Please don't understand me wrong: Your answer is great! Still I will wait a little bit before marking it as accepted.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.