請注意,如果您的 HTML 沒有包含 doctype 宣告,則 getElementById 將永遠回傳 null。
(PHP 5, PHP 7, PHP 8)
DOMDocument::getElementById — 搜尋具有特定 ID 的元素
此函式類似於 DOMDocument::getElementsByTagName,但會搜尋具有指定 ID 的元素。
要使此函式正常運作,您需要使用 DOMElement::setIdAttribute 設定一些 ID 屬性,或使用定義類型為 ID 的屬性的 DTD。在後一種情況下,您需要在使用此函式之前,使用 DOMDocument::validate 或 DOMDocument::$validateOnParse 驗證您的文件。
elementId
元素的唯一 ID 值。
如果找到元素,則回傳 DOMElement;如果找不到,則回傳 null
。
範例 #1 DOMDocument::getElementById() 範例
以下範例使用 book.xml,其內容如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE books [ <!ELEMENT books (book+)> <!ELEMENT book (title, author+, xhtml:blurb?)> <!ELEMENT title (#PCDATA)> <!ELEMENT blurb (#PCDATA)> <!ELEMENT author (#PCDATA)> <!ATTLIST books xmlns CDATA #IMPLIED> <!ATTLIST books xmlns:xhtml CDATA #IMPLIED> <!ATTLIST book id ID #IMPLIED> <!ATTLIST author email CDATA #IMPLIED> ]> <?xml-stylesheet type="text/xsl" href="style.xsl"?> <books xmlns="http://books.php/" xmlns:xhtml="http://www.w3.org/1999/xhtml"> <book id="php-basics"> <title>PHP Basics</title> <author email="jim.smith@basics.php">Jim Smith</author> <author email="jane.smith@basics.php">Jane Smith</author> <xhtml:blurb><![CDATA[ <p><em>PHP Basics</em> provides an introduction to PHP.</p> ]]></xhtml:blurb> </book> <book id="php-advanced"> <title>PHP Advanced Programming</title> <author email="jon.doe@advanced.php">Jon Doe</author> </book> </books>
<?php
$doc = new DomDocument;
// 我們需要在引用 ID 之前驗證文件
$doc->validateOnParse = true;
$doc->Load('book.xml');
echo "ID 為 'php-basics' 的元素是: " . $doc->getElementById('php-basics')->tagName . "\n";
?>
上述範例將輸出:
The element whose id is 'php-basics' is: book
根據我的經驗,如果您已載入 HTML 文件,getElementById 似乎可以在沒有任何設定的情況下正常運作。但是,為了讓 getElementById 能夠處理您「建構」的簡單 XML 文件,您必須使用「xml:」前綴設定 ID,並在您建立的元素上使用 setIdAttribute,否則它將無法運作。請參閱以下範例,希望這可以節省一些人的挫折感。如果您已載入 XML 檔案,則您只需確保 ID 的屬性具有 xml: 前綴。但是,如果您開始附加 XML 文件,請不要忘記在 ID 名稱或這些元素上使用 setIdAttribute,否則當您嘗試尋找它們時,getElementById 將會回傳 null。
<?php
/* test.xml
<?xml version="1.0" encoding="utf-8"?>
<root>
<child xml:id="id_xxxxxx" status="partial">
<sub_child>Some Data</sub_child>
</child>
</root>
*/
$xmlDom = new DOMDocument('1.0', 'utf-8');
$xmlDom->formatOutput = true; // we want a nice output
// create a root
$eltRoot = $xmlDom->createElement("root");
$xmlDom->appendChild($eltRoot);
$eltChild = $xmlDom->createElement("child");
$eltRoot->appendChild($eltChild);
// add a id attribute
$attr = $xmlDom->createAttribute("xml:id"); // needs xml prefix or getElementById won't work
$eltChild->appendChild($attr);
/// create the text node and append to the created element
$tNode = $xmlDom->createTextNode("id_8120528");
$attr->appendChild($tNode);
$eltChild->setIdAttribute("xml:id", true); // VERY IMPORT or getElementById won't work
// add a id attribute
$attr = $xmlDom->createAttribute("status");
$eltChild->appendChild($attr);
/// create the text node and append to the created element
$tNode = $xmlDom->createTextNode("partial");
$attr->appendChild($tNode);
// add a subchild
$eltSub = $xmlDom->createElement("sub_child");
$eltChild->appendChild($eltSub);
$tNode = $xmlDom->createTextNode("Some Data");
$eltSub->appendChild($tNode);
$id = null;
$id = $xmlDom->getElementById("id_8120528");
assert ($id != null);
$strId = $id->getAttribute("xml:id"); // bug? empty
$strStatus = $id->getAttribute("status"); // this works!
assert ($id !=null);
$xmlDom->save("./_data/test.xml");
$xmlDom->load("./_data/test.xml"); // reloading fixes the problem
$nodeRoot = $xmlDom->getElementsByTagName("root");
if ($nodeRoot->length > 0) {
$eltRoot = $nodeRoot->item(0);
}
assert($eltRoot != null);
$id = null;
$id = $xmlDom->getElementById("id_8120528");
assert ($id != null);
$strId = $id->getAttribute("xml:id"); // this works now!
$strStatus = $id->getAttribute("status"); // this works!
?>
在 XHTML 文件中搜尋特定元素時,getElementById() 出現了一些問題。
我寫了一個小函式來解決我的問題
<?php
function getElementById($id)
{
$xpath = new DOMXPath($this->domDocument);
return $xpath->query("//*[@id='$id']")->item(0);
}
?>
讓你省去一個大麻煩以及翻閱大量文件的时间 -
不要使用 $object->setAttribute('id', 'id_name_here')
請使用:$object->setAttribute('xml:id', 'id_name_here')
然後,要取得節點值:$domDocumentObject->getElementById('id_name_here');
xml:id 屬性應該會自動定義!!
哇!真是太簡單了......
getElementById 似乎在沒有設定 validateOnParse 為 true 的情況下也能正常運作。這很棒,因為將它設定為 true 會導致我的腳本出現一些效能問題。
如果您嘗試將 getElementById 用於根據 xsd 檔案驗證的 xml 檔案,則必須先使用 schemaValidate 函式,否則 getElementById 將返回 null。
範例
$dom = new DomDocument();
$dom->load("users.xml");
$dom->schemaValidate("users.xsd");
$curruser = $dom->getElementById($user->name);
要設定一個可供 $dom->getElementById() 使用的隱藏 id,請套用 setAttribute('id', true),如下例所示
$createItemNode = function ($data) use ($dom) {
$node = $dom->createElement("Item");
$node->setAttribute('id', $data->id);
$node->setAttribute('hed', $data->hed);
$node->setAttribute('run_time', $data->run_time);
$node->setAttribute('date', $data->date);
// 在內部將 id 標記為 'xml:id',以便 getElementById 運作。手動將 xml:id 新增至標籤會導致 loadXML 拋出錯誤 DOMDocument: xml:id is not a NCName in Entity
$node->setIdAttribute('id', true);
return $node;
};
使用 $node->setIdAttribute('id', true) 後,$dom->getElementById($id) 將會正常運作
當您執行 $dom->saveXML() 時,最終文件將不包含任何 xml:id 屬性。
有時無法從 DTD 驗證文件以使用 getElementById(例如,當 XHtml 文件中尚未包含 head 和 body 元素時:驗證失敗)。
幸運的是,這個函式支援 xml:id :)
這可能很有用。
http://www.w3.org/TR/xml-id/
如果您的 XML 文件沒有將 "id" 屬性定義為 ID 的 DTD,那麼最簡單的方法是使用 XPath->query() 來尋找符合 "//[@id='x']" 的元素。
您不想使用「xml:id」嗎?
這裡有一個 relaxNG 的技巧(使用通用 schema)
(使用 libxml 2.6.26 測試)
<?php
$doc = new DOMDocument();
$doc->load(...);
$rng = '
<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
<start>
<element>
<anyName/>
<ref name="anythingID"/>
</element>
</start>
<define name="anythingID">
<zeroOrMore>
<choice>
<element>
<anyName/>
<ref name="anythingID"/>
</element>
<attribute name="id">
<data type="ID"/>
</attribute>
<zeroOrMore>
<attribute><anyName/></attribute>
</zeroOrMore>
<text/>
</choice>
</zeroOrMore>
</define>
</grammar>
';
$doc->relaxNGValidateSource($rng);
var_dump($doc->getElementById('id1'));
?>
請注意,ID 值必須是有效的
- 整數無效!
- 參考 http://www.w3.org/TR/REC-xml/#id
- => (字母 | '_' | ':') ( 字母 | 數字 | '.' | '-' | '_' | ':' | 組合字元 | 擴展字元 )*