I have a library that composes HTML elements using the DOM classes. I want to also use the DOM functionality to go deep into my composed elements and check specific child elements for values.
For example, here's element produced by a class called YesNoControl
:
<div id="yes_no">
<input id="yes_no_1" name="yes_no" value="1" type="radio"/>
<label for="yes_no_1">Yes</label>
<input id="yes_no_2" name="yes_no" value="2" type="radio"/>
<label for="yes_no_2">No</label>
</div>
A PHPUnit test should look something like this:
$element = new YesNoControl();
$element_dom = $element->toDOMDocument(); // This method renders the object to a DOMDocument object.
$element_dom->validate();
$this->assertInstanceOf(\\DOMDocument::class, $element_dom);
$input = $element_dom->getElementById('yes_no_1');
$this->assertInstanceOf(\DOMNode::class, $input);
$this->assertEquals('1', $input->getAttribute('yes_no_1'));
The problem is that $input
always comes back null
.
In my research, I found that getElementById()
works only if the document has a DOCTYPE HTML tag. In my builder, I'm creating the document the plain-and-simple way:
$document = new \DOMDocument();
I tried adding the implementation tag to the document directly after creating the document thusly:
$implementation = new \DOMImplementation();
$document->appendChild($implementation->createDocumentType('HTML'));
However, this produces invalid elements with the <!DOCTYPE HTML>
incorrectly inserted, like this example:
<div id="yes_no">
<!DOCTYPE HTML>
<input id="yes_no_1" name="yes_no" value="1" type="radio"/>
<label for="yes_no_1">Yes</label>
<input id="yes_no_2" name="yes_no" value="2" type="radio"/>
<label for="yes_no_2">No</label>
</div>
I see quite a few answers that mention putting <!DOCTYPE HTML>
into HTML being interpreted (e.g. this one). But I'm not starting from HTML; I'm composing an element and letting the DOM library write the HTML.
I've also tried creating an implementation on the fly, per this answer:
$element_dom = $element->toDOMDocument(); // This method renders the object to a DOMDocument object.
$element_dom->validate();
$dtd = '<!ELEMENT input (#PCDATA)>';
$systemId = 'data://text/plain;base64,'.base64_encode($dtd);
$implementation = new \DOMImplementation;
$element_dom->appendChild($$implementation->createDocumentType('HTML', null, $systemId));
$input = $element_dom->getElementById('yes_no_1');
$this->assertInstanceOf(\DOMNode::class, $input);
// Failed asserting that null is an instance of class "DOMNode".
I've also tried using XPath to get the value:
$xpath = new \DOMXPath($element_dom);
$input = $xpath->query("//*[@id=yes_no_1]")->item(0);
$this->assertInstanceOf(\DOMNode::class, $input);
// Failed asserting that null is an instance of class "DOMNode".
So far, nothing I have tried is working. How do I need to structure my test so that it can find yes_no_1
?