Repository navigation
Keep the closing "?" of processing instructions in html5qp() documents - #113
Merged
Merged
Conversation
html()/writeHTML() go through libxml's HTML serializer, which relies on the terminator being in the PI data. Masterminds never leaves it there, and saveDocumentHTML() only restores it for a QueryPath\Document. Retype the Masterminds document as a Document so it gets the same treatment. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #113 +/- ##
============================================
+ Coverage 90.69% 90.98% +0.28%
- Complexity 1424 1425 +1
============================================
Files 25 25
Lines 3170 3171 +1
============================================
+ Hits 2875 2885 +10
+ Misses 295 286 -9 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
html()andwriteHTML()dropped the closing?of every processing instruction in anhtml5qp()document:libxml's HTML serializer expects the
?to already be in the PI data. #68 handles that insaveDocumentHTML(), but only for documents that are aQueryPath\Document. Masterminds builds a plainDOMDocument, so the?was never put back.The fix
QueryPath::withHTML5()now retypes the document Masterminds builds as aQueryPath\Document. It callsregisterNodeClass(DOMDocument::class, Document::class), releases the original wrapper, and fetches the document again through its doctype node. PHP builds the new wrapper from the registered class.DOM::createDocument()already depends on this same rebuild behaviour.The document is otherwise exactly what Masterminds produces. On PHP 7.4, 8.2 and 8.5,
html(),html5(),xml(), theinner*()methods,text()andwriteHTML()gave byte-identical output before and after the change for a set of documents: non-ASCII text, an HTML 4 doctype, a document with no<html>, SVG/MathML,tests/data.htmland the file-path route. The document properties (encoding,documentURI,standalone, ...) matched as well.Why not the issue's two candidates
target_document: Masterminds only adds the doctype to a document it creates itself. Appending a doctype fromDOMImplementation::createDocumentType()to the target looks fine ($doc->doctypeis set), but on PHP < 8.4 it doesn't set libxml'sintSubset, sosaveHTML()still leaves the doctype out. Seeding the target withloadXML('<!DOCTYPE html><html/>')does work, but it setsdocumentURIto the working directory, and resetting it gives""instead ofNULL. That is a smaller change, but still a change.registerNodeClass('DOMElement', …): this would change the class of every element callers get back.The retype changes nothing except the class of the document.
Behaviour change
html5qp(...)->document()now returns aQueryPath\Document, which extendsDOMDocument, just like documents fromqp()andhtmlqp(). A Masterminds document the caller builds and passes toqp()stays a plainDOMDocumentand is still written as-is.Tests
tests/Issues/Issue86Test.phpcovers:html5qp()column of the issue's table:html(),html5(),xml(),innerHTML(),innerHTML5(),innerXML(),writeHTML()(printed and to a file),writeHTML5()andwriteXML(). It also covers loading from a file path.html()andwriteHTML()still emit<!DOCTYPE html>.ownerDocument, content ending in??>round-trips, andwriteHTML()leaves the PI data unchanged.htmlqp(),qp(), and caller-suppliedDOMDocuments (from libxml and from Masterminds) behave as before.Six of these tests fail without the fix. The full suite and both lints pass.
Fixes #86.
🤖 Generated with Claude Code