PHP Conference Japan 2024

DOMDocument::importNode

(PHP 5、PHP 7、PHP 8)

DOMDocument::importNode將節點匯入目前的檔案

描述

public DOMDocument::importNode(DOMNode $node, bool $deep = false): DOMNode|false

此函式會傳回要匯入的節點副本,並將其與目前的檔案建立關聯。

參數

node

要匯入的節點。

deep

如果設為 true,此方法將遞迴匯入 node 底下的子樹。

注意:

若要複製節點屬性,deep 需要設為 true

傳回值

複製的節點或 false,如果無法複製。

錯誤/例外

如果無法匯入節點,則會擲回 DOMException

範例

範例 1 DOMDocument::importNode() 範例

在檔案之間複製節點。

<?php

$orgdoc
= new DOMDocument;
$orgdoc->loadXML("<root><element><child>text in child</child></element></root>");

// 我們想要匯入到新檔案的節點
$node = $orgdoc->getElementsByTagName("element")->item(0);


// 建立新檔案
$newdoc = new DOMDocument;
$newdoc->formatOutput = true;

// 新增一些標記
$newdoc->loadXML("<root><someelement>text in some element</someelement></root>");

echo
"在複製節點到其中的 '新檔案' 之前:\n";
echo
$newdoc->saveXML();

// 將節點及其所有子節點匯入檔案
$node = $newdoc->importNode($node, true);
// 然後將其附加到 "<root>" 節點
$newdoc->documentElement->appendChild($node);

echo
"\n在複製節點到其中的 '新檔案' 之後:\n";
echo
$newdoc->saveXML();
?>

以上範例會輸出

The 'new document' before copying nodes into it:
<?xml version="1.0"?>
<root>
  <someelement>text in some element</someelement>
</root>

The 'new document' after copying the nodes into it:
<?xml version="1.0"?>
<root>
  <someelement>text in some element</someelement>
  <element>
    <child>text in child</child>
  </element>
</root>

新增附註

使用者貢獻的附註 11 則附註

5
rikdnua at mail dot ru
11 年前
在 PHP 5.2.9-2 和 PHP 5.2.17 中,importNode($node, false) 的行為不同。
第二個選項明確設為 false。在 PHP 5.2.9-2 中,importNode() 會匯入**沒有**屬性的元素。在 PHP 5.2.17 中,匯入的元素**包含**其屬性。
<?php
$xml
="
<html>
<a href='yandex.com'>Yandex.com</a>
<a href='rik.dn.ua'>RiK.dn.ua</a>
</html>
"
;
$doc=new domDocument('1.0');
$doc->loadXML($xml);
$list=$doc->getElementsByTagName('a');
$doc1=new domDocument('1.0');
$doc1->formatOutput=true;
for(
$i=0; $i<$list->length; $i++) $doc1->appendChild($doc1->importNode($list->item($i), false));
$doc1->save('file.xml');
?>

file.xml PHP 5.2.9-2
<?xml version="1.0"?>
<a/>
<a/>

file.xml PHP 5.2.17
<?xml version="1.0"?>
<a href="yandex.com"/>
<a href="rik.dn.ua"/>
3
mailme at sove dot nl
16 年前
DOMDocument->importNode 的第二個引數為 false 會遺留屬性。若要修正此問題

$__DOM->importNode
(
$__INPUT->cloneNode(false), true
);

$__DOM (DOMDocument) 將匯入 $__INPUT 節點 (DOMElement),**包含**屬性。
3
c dot 1 at smithies dot org
15 年前
假設 $source 和 $dest 是 DOMDocument 的執行個體。假設 $sourcedoc 包含具有 ID 'sourceID' 的元素,而 $destdoc 包含具有 ID 'destID' 的元素。假設我們已經設定好來源和目標元素變數,如下所示

<?php
$src
= $sourcedoc->getElementById('sourceID');
$dst = $destdoc->getElementById('destID');
?>

最後,假設 $sel 有多個子節點。

若要將 $src 的子元素匯入為 $dst 的子元素,您可能會執行類似下列的操作

<?php
$src
= $dest->importNode($src, TRUE);

foreach (
$src->childNodes as $el) $dst->appendChild($el);
?>

但這無法運作。foreach 會感到混淆,因為(如下所述)將匯入的元素附加到相同檔案中的另一個現有元素時,會將其從目前的父元素中移除。

因此,應使用下列技巧

<?php
foreach ($src->childNodes as $el) $dst->appendChild($destdoc->importNode($el, TRUE));
?>
3
Fitopaldi
19 年前
importNode 會回傳要匯入節點的副本,並將其與目前的文檔關聯,但不會將節點匯入目前的 DOMDocument。使用 appendChild 將節點的副本匯入目前的 DOMDocument。

<?
$domNode = $dom->importNode($aDomNode, true);
$currentDomDocument->appendChild($domNode);
?>
2
Colin
18 年前
自 PHP 5.1.6 與 libxml 2.6.26 和 DOM/XML API 版本 20031129 起,如果嘗試從同一個文檔匯入,importNode() 不會執行任何操作。也就是說,如果您執行 $ret = importNode,然後執行 appendChild($ret) 或 insertBefore($ret, ...),您最終會*移動*節點,而不是得到副本。

如果您希望 importNode 給您來源的副本(在此情況下為深層複製),那麼您必須考慮它們來自同一個文檔。此函式解決了這個問題

<?
// 將 $b 匯入 $a 的文檔
function myimport($a, $b)
{
if ($a->ownerDocument->isSameNode($b->ownerDocument))
{
$temp = new DOMDocument();
$ret = $temp->importNode($b, TRUE);
return $a->ownerDocument->importNode($ret, TRUE);
}
else
{
return $a->ownerDocument->importNode($b, TRUE);
}
}
?>

(此函式是為此筆記新編寫的,但我參考了另一個有效的函式。)

此函式會檢查文檔是否相同,並使用新的文檔(保證以這種方式不同)強制複製到 $temp,然後強制複製回 $a->ownerDocument。

顯然,尚未進行任何錯誤檢查。
1
andy dot clark at dial dot pipex dot com
18 年前
importNode 的一個有用用途是將一個節點複製到另一個節點上。

function CopyXMLNode($SourceNode,$DestNode)
{
if ($SourceNode->nodeName != '#text')
{
//複製此節點
$node = $DestNode->ownerDocument->importNode($SourceNode, true);
$node = $DestNode->appendChild($node);
//現在複製子節點
foreach ($SourceNode->childNodes AS $item)
{
$this->CopyXMLNode($item,$node);
}
}
}
2
mark at 4inloop dot de
17 年前
當您省略第二個參數或輸入 false 時,不僅子節點會被省略。節點的屬性也會被切斷。
2
adjwilli
18 年前
使用 PHP 編輯 XML 可能是個麻煩,所以這裡有一個腳本,可以透過 POST 將 XML 節點替換為使用者提供的節點。通常,在執行此操作之前,最好對 $_POST['xml'] 進行驗證檢查並清除其他內容。

基本上,這個腳本會預期一個使用者提供的節點,稱為 $_POST['xml'],以及您要替換的原始文檔中節點的 XPath,稱為 $_POST['XPath']。它也會從 $xml 加載原始 XML 文檔。函式 nodeRunner 從您正在編輯的文檔的根節點和根元素的 XPath 開始(這些更多是為了使遞迴更容易)。

$doc = new DOMDocument();
$doc->loadXML($xml); // $xml 預期是一個 XML 字串

function nodeRunner ($node,$xpath) {
global $doc;
if ($xpath == $_POST['XPath']) {

$xmlPost = new DOMDocument();
$xmlPost->loadXML($_POST['xml']);

$newNode = $doc->importNode($xmlPost->firstChild,true);

$node->parentNode->replaceChild($newNode,$node);
} else {

$page = 1;
$section = 1;

if ($node->hasChildNodes()) {
foreach ($node->childNodes as $nodling) {
$nodeName = $nodling->nodeName;
if ($nodeName == 'page' || $nodeName == 'section') {
nodeRunner ($nodling,$xpath."/".$nodeName."[".$$nodeName."]");
$$nodeName++;
}
}
}
}
}

nodeRunner ($doc->documentElement,"/root[1]"); // /root 應該是 XPath 根元素的明確名稱

$doc->saveXML();
1
p dot reisinger at gmail dot com
15 年前
將兩個 xml 檔案合併的方法(也可以用作函式)。第一個引數是父 XML(要插入的),第二個引數是子 XML(要插入的),第三個是可選引數,指定要插入子 XML 的父標籤。如果未指定,則子 XML 會插入為最後一個元素,就在根結尾之前
<?php
protected function joinXML($parent, $child, $tag = null)
{
$DOMChild = new DOMDocument;
$DOMChild->loadXML($child);
$node = $DOMChild->documentElement;

$DOMParent = new DOMDocument;
$DOMParent->formatOutput = true;
$DOMParent->loadXML($parent);

$node = $DOMParent->importNode($node, true);

if (
$tag !== null) {
$tag = $DOMParent->getElementsByTagName($tag)->item(0);
$tag->appendChild($node);
} else {
$DOMParent->documentElement->appendChild($node);
}

return
$DOMParent->saveXML();
}
?>
1
p dot reisinger at gmail dot com
15 年前
當您使用以下函式/方法時,PHP 會自動插入命名空間(如果您有)。如果您想要完全合併 XML 檔案,則可以使用佔位符並將 XML 視為字串。
<?php
function joinXMLStrings($file1, $file2)
{
//移除 XML 宣告
$file2 = trim(preg_replace('/<\?xml.*\?>/', '', $file2, 1));

//將 file2 插入到第一個檔案中佔位符的位置
$file1 = trim(preg_replace('/<\?file2\s\?>/', $file2, $file1, 1));
}
?>

所以函式看起來像這樣,您會插入兩個 XML 檔案。第一個檔案必須有一個佔位符(您將在其中插入 file2)。在本例中,佔位符將是 <?file2 ?>

!!!這僅用於說明 - 請在使用前測試
1
stomas
18 年前
我認為這應該做同樣的事情

<?
// 將 $b 匯入 $a 的文檔
function myimport($a, $b)
{
if ($a->ownerDocument->isSameNode($b->ownerDocument))
{
return $b->cloneNode(TRUE);
}
else
{
return $a->ownerDocument->importNode($b, TRUE);
}
}
?>
To Top