Please note that if your HTML does not contain a doctype declaration, then getElementById will always return null.(PHP 5, PHP 7, PHP 8)
DOMDocument::getElementById β ΠΡΠ΅Ρ ΡΠ»Π΅ΠΌΠ΅Π½Ρ Ρ ΠΎΠΏΡΠ΅Π΄Π΅Π»ΡΠ½Π½ΡΠΌ ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡΠΎΠΌ
ΠΡΠ° ΡΡΠ½ΠΊΡΠΈΡ ΠΏΠΎΡ ΠΎΠΆΠ° Π½Π° DOMDocument::getElementsByTagName, Π½ΠΎ ΠΈΡΠ΅Ρ ΡΠ»Π΅ΠΌΠ΅Π½Ρ Ρ Π·Π°Π΄Π°Π½Π½ΡΠΌ ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡΠΎΠΌ.
ΠΠ»Ρ ΡΠ°Π±ΠΎΡΡ ΡΡΠΎΠΉ ΡΡΠ½ΠΊΡΠΈΠΈ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ ΡΡΡΠ°Π½ΠΎΠ²ΠΈΡΡ Π°ΡΡΠΈΠ±ΡΡΡ ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡΠΎΠ² Ρ ΠΏΠΎΠΌΠΎΡΡΡ DOMElement::setIdAttribute, Π»ΠΈΠ±ΠΎ DTD, ΠΊΠΎΡΠΎΡΡΠΉ ΠΎΠΏΡΠ΅Π΄Π΅Π»ΡΠ΅Ρ Π°ΡΡΠΈΠ±ΡΡ ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡΠ° ΡΠΈΠΏΠ°. Π ΠΏΠΎΡΠ»Π΅Π΄Π½Π΅ΠΌ ΡΠ»ΡΡΠ°Π΅ ΠΏΠ΅ΡΠ΅Π΄ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ ΡΡΠΎΠΉ ΡΡΠ½ΠΊΡΠΈΠΈ Π²Π°ΠΌ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ Π±ΡΠ΄Π΅Ρ ΠΏΡΠΎΠ²Π΅ΡΠΈΡΡ Π΄ΠΎΠΊΡΠΌΠ΅Π½Ρ Ρ ΠΏΠΎΠΌΠΎΡΡΡ DOMDocument::validate ΠΈΠ»ΠΈ DOMDocument::$validateOnParse.
elementIdΠ£Π½ΠΈΠΊΠ°Π»ΡΠ½ΡΠΉ Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡΠ° ΡΠ»Π΅ΠΌΠ΅Π½ΡΠ°.
ΠΠΎΠ·Π²ΡΠ°ΡΠ°Π΅Ρ ΠΎΠ±ΡΠ΅ΠΊΡ 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;
// ΠΡΠΆΠ½ΠΎ ΠΏΡΠΎΠ²Π΅ΡΠΈΡΡ Π΄ΠΎΠΊΡΠΌΠ΅Π½Ρ ΠΏΠ΅ΡΠ΅Π΄ ΡΠ΅ΠΌ ΠΊΠ°ΠΊ ΡΡΡΠ»Π°ΡΡΡΡ ΠΏΠΎ ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡΡ
$doc->validateOnParse = true;
$doc->load('examples/book.xml');
echo "ΠΠ»Π΅ΠΌΠ΅Π½Ρ Ρ ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡΠΎΠΌ 'php-basics': " . $doc->getElementById('php-basics')->tagName . "\n";
?>Π Π΅Π·ΡΠ»ΡΡΠ°Ρ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ ΠΏΡΠΈΠ²Π΅Π΄ΡΠ½Π½ΠΎΠ³ΠΎ ΠΏΡΠΈΠΌΠ΅ΡΠ°:
ΠΠ»Π΅ΠΌΠ΅Π½Ρ Ρ ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡΠΎΠΌ 'php-basics': book
Please note that if your HTML does not contain a doctype declaration, then getElementById will always return null.From my experience, getElementById seem to work fine without any setups if you have loaded a HTML document. But in order for getElementById to work with a simple XML document that you've "constructed", you have to set up the id with "xml:" prefix and use setIdAttribute on the element you created or it won't work. See following example, hope this will save someone's frustration. If you have loaded the xml file, then all you have to make sure is the ID has a xml: prefix for the attribute. But if you start to append the XML document, don't forget to setIdAttribute on the id name or those elements or getElementById will return null when you try to find them.
<?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!
?>Had some issues with getElementById() while searching for a specific element in a XHTML document.
I wrote a small function what was solving my problem:
<?php
function getElementById($id)
{
$xpath = new DOMXPath($this->domDocument);
return $xpath->query("//*[@id='$id']")->item(0);
}
?>SAVE YOURSELF A MAJOR HEADACHE AND A LOT OF SEARCHING THROUGH DOCUMENTATION -
Instead of using $object->setAttribute('id', 'id_name_here')
USE THIS: $object->setAttribute('xml:id', 'id_name_here')
Then, to get the node value: $domDocumentObject->getElementById('id_name_here');
The xml:id attribute should AUTOMATICALLY be defined!!
Woohoo! That was easy......It seems getElementById works fine without setting validateOnParse to true. Which is nice since setting this to true caused some performance problems with my script.If you're trying to use getElementById with a xml file validated on a xsd file you must first use the schemaValidate function or getElementById will return null
Example:
$dom = new DomDocument();
$dom->load("users.xml");
$dom->schemaValidate("users.xsd");
$curruser = $dom->getElementById($user->name);To set a hidden id that can be used by $dom->getElementById() apply setAttribute('id', true) as in the following example
$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);
// Internally mark the id as 'xml:id' for getElementById to work. Adding xml:id manually to the tag will cause loadXML to throw an error DOMDocument: xml:id is not a NCName in Entity
$node->setIdAttribute('id', true);
return $node;
};
With $node->setIdAttribute('id', true), $dom->getElementById($id) will work
When you do $dom->saveXML(), the final doc will not contain any xml:id attribute.Validating a document from a DTD so as to use getElementById is sometimes impossible (for example when the head and body elements are not included yet in a XHtml document : the validation failed).
Fortunately, xml:id is supported by this function :)
That may be useful.
http://www.w3.org/TR/xml-id/If your XML document does not have a DTD that defines the "id" attribute as an ID, then the easiest thing to do is to use XPath->query() to find an element that matches "//[@id='x']"You don't want to use "xml:id" ?
Here is the relaxNG trick (with a generic schema):
(tested with 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'));
?>
Note that ID values must be valid ones :
- integers do no work!
- @see http://www.w3.org/TR/REC-xml/#id
- => (Letter | '_' | ':') ( Letter | Digit | '.' | '-' | '_' | ':' | CombiningChar | Extender )*