请注意,如果您的 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="[email protected]">Jim Smith</author> <author email="[email protected]">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="[email protected]">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; // 我们想要一个漂亮的输出
// 创建一个根节点
$eltRoot = $xmlDom->createElement("root");
$xmlDom->appendChild($eltRoot);
$eltChild = $xmlDom->createElement("child");
$eltRoot->appendChild($eltChild);
// 添加一个 id 属性
$attr = $xmlDom->createAttribute("xml:id"); // 需要 xml 前缀,否则 getElementById 无法工作
$eltChild->appendChild($attr);
/// 创建文本节点并附加到创建的元素
$tNode = $xmlDom->createTextNode("id_8120528");
$attr->appendChild($tNode);
$eltChild->setIdAttribute("xml:id", true); // 非常重要,否则 getElementById 无法工作
// 添加一个 id 属性
$attr = $xmlDom->createAttribute("status");
$eltChild->appendChild($attr);
/// 创建文本节点并附加到创建的元素
$tNode = $xmlDom->createTextNode("partial");
$attr->appendChild($tNode);
// 添加一个子节点
$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? 空白
$strStatus = $id->getAttribute("status"); // 这有效!
assert ($id !=null);
$xmlDom->save("./_data/test.xml");
$xmlDom->load("./_data/test.xml"); // 重新加载解决了问题
$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"); // 这现在有效!
$strStatus = $id->getAttribute("status"); // 这有效!
?>
在 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);
要设置一个隐藏的 ID,它可以被 $dom->getElementById() 使用,请应用 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 不是实体中的 NCName
$node->setIdAttribute('id', true);
return $node;
};
使用 $node->setIdAttribute('id', true),$dom->getElementById($id) 将起作用
当您执行 $dom->saveXML() 时,最终文档将不包含任何 xml:id 属性。
从 DTD 验证文档以使用 getElementById 有时是不可能的(例如,当头元素和主体元素尚未包含在 XHTML 文档中时:验证失败)。
幸运的是,此函数支持 xml:id :)
这可能有用。
http://www.w3.org/TR/xml-id/
如果您的 XML 文档没有定义“id”属性为 ID 的 DTD,那么最简单的方法是使用 XPath->query() 查找匹配 "//[@id='x']" 的元素
您不想使用 "xml:id" 吗?
以下是 relaxNG 技巧(使用通用模式)
(在 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 值必须是有效的
- 整数不起作用!
- @see http://www.w3.org/TR/REC-xml/#id
- => (Letter | '_' | ':') ( Letter | Digit | '.' | '-' | '_' | ':' | CombiningChar | Extender )*