代码之家  ›  专栏  ›  技术社区  ›  thomasrutter

dom:如何导入节点并给它们不同的名称空间前缀

  •  3
  • thomasrutter  · 技术社区  · 14 年前

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

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

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

    编辑:根据我答案中的解释,我发现其实我不需要这么做。我误解了xml中的名称空间。

    2 回复  |  直到 12 年前
        1
  •  0
  •   VolkerK    14 年前

    那么您可能需要编写自己的导入代码。例如。

    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>
    
        2
  •  0
  •   thomasrutter    14 年前

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

    在某些情况下,名称空间前缀是一个很好的快捷方式,但仅在不同名称空间的另一个文档中包含一个文档时不需要。