3

我熟悉用于从其他文档元素导入节点树的DOMDocument::importNode方法。

但是,我想知道是否可以在导入节点树时自动更改节点树上的命名空间前缀,也就是说,为该命名空间的所有节点指定一个新前缀。

假设节点,在它们现有的文档中,都具有“名称”、“身份”等名称。将它们导入我的新文档时,它们将与其他命名空间并排,因此我希望它们显示为“nicnames:name”、“nicnames:identity”等。我希望能够以编程方式更改此前缀,以便在另一个上下文中我可以将它们导入为例如“myprefix:name”、“myprefix:identity”,具体取决于它们导入的文档。

编辑:根据我的回答中的解释,我发现我实际上不需要这样做。我误解了 XML 中的名称空间。

4

2 回答 2

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>
于 2010-04-07T08:14:35.560 回答
0

我发现我误解了 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>

命名空间前缀在某些情况下是一个很好的快捷方式,但当只是将一个文档包含在另一个不同命名空间的另一个文档中时,就没有必要了。

于 2010-04-10T02:39:48.213 回答