DOM: how to import nodes and provide them with a different namespace prefix

I am familiar with the DOMDocument :: importNode method for importing a tree of nodes from some other document element.

However, I was wondering if I can automatically change the namespace prefix on the node tree upon import, i.e. specify a new prefix for all nodes in this namespace.

Say that the nodes in your existing document have names like "name", "identifier", etc. When importing them into a new document, they will be next to other namespaces, so I would like them to appear as "names: name", "names: identifier", etc. I would like to be able to change this prefix programmatically so that in another context I can import them, for example, "myprefix: name", "myprefix: identity" depending on the document being imported.

Edit: according to the explanation in my answer, I realized that I really don't need to do this. I misunderstood namespaces in XML.

+3
source share
2 answers

, XML. , .

, XML, , . .

, xmlns, , xmlns , , .

, , :

<record xmlns="namespace1">
  <person:surname xmlns:person="namespace2">Smith</person:surname>
</record>

<record xmlns="namespace1">
  <surname xmlns="namespace2">Smith</person>
</record>

, , .

0

, . .

function importNS(DOMNode $target, DOMNode $source, $fnImportElement, $fnImportAttribute) {
  switch($source->nodeType) {
    case XML_ELEMENT_NODE:
      // invoke the callback that creates the new DOMElement node
      $newNode = $fnImportElement($target->ownerDocument, $source);
      if ( !is_null($newNode) && !is_null($source->attributes) ) {
        foreach( $source->attributes as $attr) {
          importNS($newNode, $attr, $fnImportElement, $fnImportAttribute);
        }
      }
      break;
    case XML_ATTRIBUTE_NODE:
      // invoke the callback that creates the new DOMAttribute node
      $newNode = $fnImportAttribute($target->ownerDocument, $source);
      break;
    default:
      // flat copy
      $newNode = $target->ownerDocument->importNode($source);
  }

  if ( !is_null($newNode) ) {
    // import all child nodes
    if ( !is_null($source->childNodes) ) {
      foreach( $source->childNodes as $c) {
        importNS($newNode, $c, $fnImportElement, $fnImportAttribute);
      }
    }
    $target->appendChild($newNode);
  }
}

$target = new DOMDocument;
$target->loadxml('<foo xmlns:myprefix="myprefixUri"></foo>');

$source = new DOMDocument;
$source->loadxml('<a>
  <b x="123">...</b>
</a>');

$fnImportElement = function(DOMDocument $newOwnerDoc, DOMElement $e) {
  return $newOwnerDoc->createElement('myprefix:'.$e->localName);
};

$fnImportAttribute = function(DOMDocument $newOwnerDoc, DOMAttr $a) {
  // could use namespace here, too....
  return $newOwnerDoc->createAttribute($a->name);
};

importNS($target->documentElement, $source->documentElement, $fnImportElement, $fnImportAttribute);
echo $target->savexml();

<?xml version="1.0"?>
<foo xmlns:myprefix="myprefixUri"><myprefix:a>
  <myprefix:b x="123">...</myprefix:b>
</myprefix:a></foo>
0

Source: https://habr.com/ru/post/1740104/


All Articles