Commit a16b5639 authored by alexpott's avatar alexpott

Issue #2195745 by sun: Replace _filter_htmlcorrector() with a utility class in core.

parent e71d749e
......@@ -5,6 +5,9 @@
* API functions for processing and sending e-mail.
*/
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Xss;
/**
* Composes and optionally sends an e-mail message.
*
......@@ -288,7 +291,7 @@ function drupal_html_to_text($string, $allowed_tags = NULL) {
$allowed_tags = isset($allowed_tags) ? array_intersect($supported_tags, $allowed_tags) : $supported_tags;
// Make sure tags, entities and attributes are well-formed and properly nested.
$string = _filter_htmlcorrector(filter_xss($string, $allowed_tags));
$string = Html::normalize(Xss::filter($string, $allowed_tags));
// Apply inline styles.
$string = preg_replace('!</?(em|i)((?> +)[^>]*)?>!i', '/', $string);
......
<?php
/**
* @file
* Contains \Drupal\Component\Utility\Html.
*/
namespace Drupal\Component\Utility;
/**
* Provides DOMDocument helpers for parsing and serializing HTML strings.
*/
class Html {
/**
* Normalizes an HTML snippet.
*
* This function is essentially \DOMDocument::normalizeDocument(), but
* operates on an HTML string instead of a \DOMDocument.
*
* @param string $html
* The HTML string to normalize.
*
* @return string
* The normalized HTML string.
*/
public static function normalize($html) {
$document = static::load($html);
return static::serialize($document);
}
/**
* Parses an HTML snippet and returns it as a DOM object.
*
* This function loads the body part of a partial (X)HTML document and returns
* a full \DOMDocument object that represents this document.
*
* Use \Drupal\Component\Utility\Html::serialize() to serialize this
* \DOMDocument back to a string.
*
* @param string $html
* The partial (X)HTML snippet to load. Invalid markup will be corrected on
* import.
*
* @return \DOMDocument
* A \DOMDocument that represents the loaded (X)HTML snippet.
*/
public static function load($html) {
$document = <<<EOD
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head>
<body>!html</body>
</html>
EOD;
// PHP's \DOMDocument serialization adds straw whitespace in case the markup
// of the wrapping document contains newlines, so ensure to remove all
// newlines before injecting the actual HTML body to process.
$document = strtr($document, array("\n" => '', '!html' => $html));
$dom = new \DOMDocument();
// Ignore warnings during HTML soup loading.
@$dom->loadHTML($document);
return $dom;
}
/**
* Converts the body of a \DOMDocument back to an HTML snippet.
*
* The function serializes the body part of a \DOMDocument back to an (X)HTML
* snippet. The resulting (X)HTML snippet will be properly formatted to be
* compatible with HTML user agents.
*
* @param \DOMDocument $document
* A \DOMDocument object to serialize, only the tags below the first <body>
* node will be converted.
*
* @return string
* A valid (X)HTML snippet, as a string.
*/
public static function serialize(\DOMDocument $document) {
$body_node = $document->getElementsByTagName('body')->item(0);
$html = '';
foreach ($body_node->getElementsByTagName('script') as $node) {
static::escapeCdataElement($node);
}
foreach ($body_node->getElementsByTagName('style') as $node) {
static::escapeCdataElement($node, '/*', '*/');
}
foreach ($body_node->childNodes as $node) {
$html .= $document->saveXML($node);
}
return $html;
}
/**
* Adds comments around a <!CDATA section in a \DOMNode.
*
* \DOMDocument::loadHTML() in \Drupal\Component\Utility\Html::load() makes
* CDATA sections from the contents of inline script and style tags. This can
* cause HTML4 browsers to throw exceptions.
*
* This function attempts to solve the problem by creating a
* \DOMDocumentFragment to comment the CDATA tag.
*
* @param \DOMNode $node
* The element potentially containing a CDATA node.
* @param string $comment_start
* (optional) A string to use as a comment start marker to escape the CDATA
* declaration. Defaults to '//'.
* @param string $comment_end
* (optional) A string to use as a comment end marker to escape the CDATA
* declaration. Defaults to an empty string.
*/
public static function escapeCdataElement(\DOMNode $node, $comment_start = '//', $comment_end = '') {
foreach ($node->childNodes as $child_node) {
if ($child_node instanceof \DOMCdataSection) {
$embed_prefix = "\n<!--{$comment_start}--><![CDATA[{$comment_start} ><!--{$comment_end}\n";
$embed_suffix = "\n{$comment_start}--><!]]>{$comment_end}\n";
// Prevent invalid cdata escaping as this would throw a DOM error.
// This is the same behavior as found in libxml2.
// Related W3C standard: http://www.w3.org/TR/REC-xml/#dt-cdsection
// Fix explanation: http://en.wikipedia.org/wiki/CDATA#Nesting
$data = str_replace(']]>', ']]]]><![CDATA[>', $child_node->data);
$fragment = $node->ownerDocument->createDocumentFragment();
$fragment->appendXML($embed_prefix . $data . $embed_suffix);
$node->appendChild($fragment);
$node->removeChild($child_node);
}
}
}
}
......@@ -5,6 +5,7 @@
* Adds bindings for client-side "text editors" to text formats.
*/
use Drupal\Component\Utility\Html;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\editor\Entity\Editor;
use Drupal\Component\Utility\NestedArray;
......@@ -661,7 +662,7 @@ function _editor_get_processed_text_fields(ContentEntityInterface $entity) {
* An array of all found UUIDs.
*/
function _editor_parse_file_uuids($text) {
$dom = filter_dom_load($text);
$dom = Html::load($text);
$xpath = new \DOMXPath($dom);
$uuids = array();
foreach ($xpath->query('//*[@data-editor-file-uuid]') as $node) {
......
......@@ -4,6 +4,8 @@
* Attach custom data fields to Drupal entities.
*/
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Template\Attribute;
use Drupal\entity\Entity\EntityViewDisplay;
......@@ -304,7 +306,7 @@ function field_cache_clear() {
* UTF-8.
*/
function field_filter_xss($string) {
return _filter_htmlcorrector(filter_xss($string, _field_filter_xss_allowed_tags()));
return Html::normalize(Xss::filter($string, _field_filter_xss_allowed_tags()));
}
/**
......
......@@ -5,6 +5,7 @@
* Field module functionality for the File module.
*/
use Drupal\Component\Utility\Html;
use Drupal\field\FieldInterface;
/**
......@@ -181,8 +182,8 @@ function theme_file_upload_help($variables) {
$descriptions = array();
if (strlen($description)) {
$descriptions[] = _filter_htmlcorrector($description);
if (!empty($description)) {
$descriptions[] = Html::normalize($description);
}
if (isset($cardinality)) {
if ($cardinality == -1) {
......
......@@ -5,6 +5,7 @@
* Framework for handling the filtering of content.
*/
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\String;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Language\Language;
......@@ -693,103 +694,6 @@ function _filter_tips($format_id, $long = FALSE) {
return $tips;
}
/**
* Parses an HTML snippet and returns it as a DOM object.
*
* This function loads the body part of a partial (X)HTML document and returns
* a full DOMDocument object that represents this document. You can use
* filter_dom_serialize() to serialize this DOMDocument back to a XHTML
* snippet.
*
* @param $text
* The partial (X)HTML snippet to load. Invalid markup will be corrected on
* import.
*
* @return
* A DOMDocument that represents the loaded (X)HTML snippet.
*/
function filter_dom_load($text) {
$dom_document = new DOMDocument();
// Ignore warnings during HTML soup loading.
@$dom_document->loadHTML('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head><body>' . $text . '</body></html>');
return $dom_document;
}
/**
* Converts a DOM object back to an HTML snippet.
*
* The function serializes the body part of a DOMDocument back to an XHTML
* snippet. The resulting XHTML snippet will be properly formatted to be
* compatible with HTML user agents.
*
* @param $dom_document
* A DOMDocument object to serialize, only the tags below
* the first <body> node will be converted.
*
* @return
* A valid (X)HTML snippet, as a string.
*/
function filter_dom_serialize($dom_document) {
$body_node = $dom_document->getElementsByTagName('body')->item(0);
$body_content = '';
foreach ($body_node->getElementsByTagName('script') as $node) {
filter_dom_serialize_escape_cdata_element($dom_document, $node);
}
foreach ($body_node->getElementsByTagName('style') as $node) {
filter_dom_serialize_escape_cdata_element($dom_document, $node, '/*', '*/');
}
foreach ($body_node->childNodes as $child_node) {
$body_content .= $dom_document->saveXML($child_node);
}
return $body_content;
}
/**
* Adds comments around the <!CDATA section in a dom element.
*
* DOMDocument::loadHTML in filter_dom_load() makes CDATA sections from the
* contents of inline script and style tags. This can cause HTML 4 browsers to
* throw exceptions.
*
* This function attempts to solve the problem by creating a DocumentFragment
* and imitating the behavior in drupal_get_js(), commenting the CDATA tag.
*
* @param $dom_document
* The DOMDocument containing the $dom_element.
* @param $dom_element
* The element potentially containing a CDATA node.
* @param $comment_start
* (optional) A string to use as a comment start marker to escape the CDATA
* declaration. Defaults to '//'.
* @param $comment_end
* (optional) A string to use as a comment end marker to escape the CDATA
* declaration. Defaults to an empty string.
*/
function filter_dom_serialize_escape_cdata_element($dom_document, $dom_element, $comment_start = '//', $comment_end = '') {
foreach ($dom_element->childNodes as $node) {
if (get_class($node) == 'DOMCdataSection') {
// See drupal_get_js(). This code is more or less duplicated there.
$embed_prefix = "\n<!--{$comment_start}--><![CDATA[{$comment_start} ><!--{$comment_end}\n";
$embed_suffix = "\n{$comment_start}--><!]]>{$comment_end}\n";
// Prevent invalid cdata escaping as this would throw a DOM error.
// This is the same behavior as found in libxml2.
// Related W3C standard: http://www.w3.org/TR/REC-xml/#dt-cdsection
// Fix explanation: http://en.wikipedia.org/wiki/CDATA#Nesting
$data = str_replace(']]>', ']]]]><![CDATA[>', $node->data);
$fragment = $dom_document->createDocumentFragment();
$fragment->appendXML($embed_prefix . $data . $embed_suffix);
$dom_element->appendChild($fragment);
$dom_element->removeChild($node);
}
}
}
/**
* Prepares variables for text format guideline templates.
*
......@@ -878,12 +782,12 @@ function _filter_html($text, $filter) {
$text = filter_xss($text, $allowed_tags);
if ($filter->settings['filter_html_nofollow']) {
$html_dom = filter_dom_load($text);
$html_dom = Html::load($text);
$links = $html_dom->getElementsByTagName('a');
foreach ($links as $link) {
$link->setAttribute('rel', 'nofollow');
}
$text = filter_dom_serialize($html_dom);
$text = Html::serialize($html_dom);
}
return trim($text);
......@@ -1127,13 +1031,6 @@ function _filter_url_trim($text, $length = NULL) {
return $text;
}
/**
* Scans the input and makes sure that HTML tags are properly closed.
*/
function _filter_htmlcorrector($text) {
return filter_dom_serialize(filter_dom_load($text));
}
/**
* Converts line breaks into <p> and <br> in an intelligent fashion.
*
......@@ -1219,7 +1116,7 @@ function _filter_html_image_secure_process($text) {
// Find the directory on the server where index.php resides.
$local_dir = DRUPAL_ROOT . '/';
$html_dom = filter_dom_load($text);
$html_dom = Html::load($text);
$images = $html_dom->getElementsByTagName('img');
foreach ($images as $image) {
$src = $image->getAttribute('src');
......@@ -1245,7 +1142,7 @@ function _filter_html_image_secure_process($text) {
// indicator. See filter_filter_secure_image_alter().
\Drupal::moduleHandler()->alter('filter_secure_image', $image);
}
$text = filter_dom_serialize($html_dom);
$text = Html::serialize($html_dom);
return $text;
}
......
......@@ -7,6 +7,7 @@
namespace Drupal\filter\Plugin\Filter;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\String;
use Drupal\Component\Utility\Unicode;
use Drupal\Component\Utility\Xss;
......@@ -30,7 +31,7 @@ class FilterCaption extends FilterBase {
public function process($text, $langcode, $cache, $cache_id) {
if (stristr($text, 'data-caption') !== FALSE || stristr($text, 'data-align') !== FALSE) {
$dom = filter_dom_load($text);
$dom = Html::load($text);
$xpath = new \DOMXPath($dom);
foreach ($xpath->query('//*[@data-caption or @data-align]') as $node) {
$caption = NULL;
......@@ -82,7 +83,7 @@ public function process($text, $langcode, $cache, $cache_id) {
$altered_html = drupal_render($filter_caption);
// Load the altered HTML into a new DOMDocument and retrieve the element.
$updated_node = filter_dom_load($altered_html)->getElementsByTagName('body')
$updated_node = Html::load($altered_html)->getElementsByTagName('body')
->item(0)
->childNodes
->item(0);
......@@ -94,7 +95,7 @@ public function process($text, $langcode, $cache, $cache_id) {
$node->parentNode->replaceChild($updated_node, $node);
}
return filter_dom_serialize($dom);
return Html::serialize($dom);
}
return $text;
......
......@@ -7,6 +7,7 @@
namespace Drupal\filter\Plugin\Filter;
use Drupal\Component\Utility\Html;
use Drupal\filter\Plugin\FilterBase;
/**
......@@ -25,7 +26,7 @@ class FilterHtmlCorrector extends FilterBase {
* {@inheritdoc}
*/
public function process($text, $langcode, $cache, $cache_id) {
return _filter_htmlcorrector($text);
return Html::normalize($text);
}
}
......@@ -7,6 +7,7 @@
namespace Drupal\filter\Tests;
use Drupal\Component\Utility\Html;
use Drupal\simpletest\DrupalUnitTestBase;
use Drupal\filter\FilterBag;
......@@ -741,117 +742,117 @@ function testUrlFilterContent() {
*/
function testHtmlCorrectorFilter() {
// Tag closing.
$f = _filter_htmlcorrector('<p>text');
$f = Html::normalize('<p>text');
$this->assertEqual($f, '<p>text</p>', 'HTML corrector -- tag closing at the end of input.');
$f = _filter_htmlcorrector('<p>text<p><p>text');
$f = Html::normalize('<p>text<p><p>text');
$this->assertEqual($f, '<p>text</p><p></p><p>text</p>', 'HTML corrector -- tag closing.');
$f = _filter_htmlcorrector("<ul><li>e1<li>e2");
$f = Html::normalize("<ul><li>e1<li>e2");
$this->assertEqual($f, "<ul><li>e1</li><li>e2</li></ul>", 'HTML corrector -- unclosed list tags.');
$f = _filter_htmlcorrector('<div id="d">content');
$f = Html::normalize('<div id="d">content');
$this->assertEqual($f, '<div id="d">content</div>', 'HTML corrector -- unclosed tag with attribute.');
// XHTML slash for empty elements.
$f = _filter_htmlcorrector('<hr><br>');
$f = Html::normalize('<hr><br>');
$this->assertEqual($f, '<hr /><br />', 'HTML corrector -- XHTML closing slash.');
$f = _filter_htmlcorrector('<P>test</P>');
$f = Html::normalize('<P>test</P>');
$this->assertEqual($f, '<p>test</p>', 'HTML corrector -- Convert uppercased tags to proper lowercased ones.');
$f = _filter_htmlcorrector('<P>test</p>');
$f = Html::normalize('<P>test</p>');
$this->assertEqual($f, '<p>test</p>', 'HTML corrector -- Convert uppercased tags to proper lowercased ones.');
$f = _filter_htmlcorrector('test<hr />');
$f = Html::normalize('test<hr />');
$this->assertEqual($f, 'test<hr />', 'HTML corrector -- Let proper XHTML pass through.');
$f = _filter_htmlcorrector('test<hr/>');
$f = Html::normalize('test<hr/>');
$this->assertEqual($f, 'test<hr />', 'HTML corrector -- Let proper XHTML pass through, but ensure there is a single space before the closing slash.');
$f = _filter_htmlcorrector('test<hr />');
$f = Html::normalize('test<hr />');
$this->assertEqual($f, 'test<hr />', 'HTML corrector -- Let proper XHTML pass through, but ensure there are not too many spaces before the closing slash.');
$f = _filter_htmlcorrector('<span class="test" />');
$f = Html::normalize('<span class="test" />');
$this->assertEqual($f, '<span class="test"></span>', 'HTML corrector -- Convert XHTML that is properly formed but that would not be compatible with typical HTML user agents.');
$f = _filter_htmlcorrector('test1<br class="test">test2');
$f = Html::normalize('test1<br class="test">test2');
$this->assertEqual($f, 'test1<br class="test" />test2', 'HTML corrector -- Automatically close single tags.');
$f = _filter_htmlcorrector('line1<hr>line2');
$f = Html::normalize('line1<hr>line2');
$this->assertEqual($f, 'line1<hr />line2', 'HTML corrector -- Automatically close single tags.');
$f = _filter_htmlcorrector('line1<HR>line2');
$f = Html::normalize('line1<HR>line2');
$this->assertEqual($f, 'line1<hr />line2', 'HTML corrector -- Automatically close single tags.');
$f = _filter_htmlcorrector('<img src="http://example.com/test.jpg">test</img>');
$f = Html::normalize('<img src="http://example.com/test.jpg">test</img>');
$this->assertEqual($f, '<img src="http://example.com/test.jpg" />test', 'HTML corrector -- Automatically close single tags.');
$f = _filter_htmlcorrector('<br></br>');
$f = Html::normalize('<br></br>');
$this->assertEqual($f, '<br />', "HTML corrector -- Transform empty tags to a single closed tag if the tag's content model is EMPTY.");
$f = _filter_htmlcorrector('<div></div>');
$f = Html::normalize('<div></div>');
$this->assertEqual($f, '<div></div>', "HTML corrector -- Do not transform empty tags to a single closed tag if the tag's content model is not EMPTY.");
$f = _filter_htmlcorrector('<p>line1<br/><hr/>line2</p>');
$f = Html::normalize('<p>line1<br/><hr/>line2</p>');
$this->assertEqual($f, '<p>line1<br /></p><hr />line2', 'HTML corrector -- Move non-inline elements outside of inline containers.');
$f = _filter_htmlcorrector('<p>line1<div>line2</div></p>');
$f = Html::normalize('<p>line1<div>line2</div></p>');
$this->assertEqual($f, '<p>line1</p><div>line2</div>', 'HTML corrector -- Move non-inline elements outside of inline containers.');
$f = _filter_htmlcorrector('<p>test<p>test</p>\n');
$f = Html::normalize('<p>test<p>test</p>\n');
$this->assertEqual($f, '<p>test</p><p>test</p>\n', 'HTML corrector -- Auto-close improperly nested tags.');
$f = _filter_htmlcorrector('<p>Line1<br><STRONG>bold stuff</b>');
$f = Html::normalize('<p>Line1<br><STRONG>bold stuff</b>');
$this->assertEqual($f, '<p>Line1<br /><strong>bold stuff</strong></p>', 'HTML corrector -- Properly close unclosed tags, and remove useless closing tags.');
$f = _filter_htmlcorrector('test <!-- this is a comment -->');
$f = Html::normalize('test <!-- this is a comment -->');
$this->assertEqual($f, 'test <!-- this is a comment -->', 'HTML corrector -- Do not touch HTML comments.');
$f = _filter_htmlcorrector('test <!--this is a comment-->');
$f = Html::normalize('test <!--this is a comment-->');
$this->assertEqual($f, 'test <!--this is a comment-->', 'HTML corrector -- Do not touch HTML comments.');
$f = _filter_htmlcorrector('test <!-- comment <p>another
$f = Html::normalize('test <!-- comment <p>another
<strong>multiple</strong> line
comment</p> -->');
$this->assertEqual($f, 'test <!-- comment <p>another
<strong>multiple</strong> line
comment</p> -->', 'HTML corrector -- Do not touch HTML comments.');
$f = _filter_htmlcorrector('test <!-- comment <p>another comment</p> -->');
$f = Html::normalize('test <!-- comment <p>another comment</p> -->');
$this->assertEqual($f, 'test <!-- comment <p>another comment</p> -->', 'HTML corrector -- Do not touch HTML comments.');
$f = _filter_htmlcorrector('test <!--break-->');
$f = Html::normalize('test <!--break-->');
$this->assertEqual($f, 'test <!--break-->', 'HTML corrector -- Do not touch HTML comments.');
$f = _filter_htmlcorrector('<p>test\n</p>\n');
$f = Html::normalize('<p>test\n</p>\n');
$this->assertEqual($f, '<p>test\n</p>\n', 'HTML corrector -- New-lines are accepted and kept as-is.');
$f = _filter_htmlcorrector('<p>دروبال');
$f = Html::normalize('<p>دروبال');
$this->assertEqual($f, '<p>دروبال</p>', 'HTML corrector -- Encoding is correctly kept.');
$f = _filter_htmlcorrector('<script>alert("test")</script>');
$f = Html::normalize('<script>alert("test")</script>');
$this->assertEqual($f, '<script>
<!--//--><![CDATA[// ><!--
alert("test")
//--><!]]>
</script>', 'HTML corrector -- CDATA added to script element');
$f = _filter_htmlcorrector('<p><script>alert("test")</script></p>');
$f = Html::normalize('<p><script>alert("test")</script></p>');
$this->assertEqual($f, '<p><script>
<!--//--><![CDATA[// ><!--
alert("test")
//--><!]]>
</script></p>', 'HTML corrector -- CDATA added to a nested script element');
$f = _filter_htmlcorrector('<p><style> /* Styling */ body {color:red}</style></p>');
$f = Html::normalize('<p><style> /* Styling */ body {color:red}</style></p>');
$this->assertEqual($f, '<p><style>
<!--/*--><![CDATA[/* ><!--*/
/* Styling */ body {color:red}
/*--><!]]>*/
</style></p>', 'HTML corrector -- CDATA added to a style element.');
$filtered_data = _filter_htmlcorrector('<p><style>
$filtered_data = Html::normalize('<p><style>
/*<![CDATA[*/
/* Styling */
body {color:red}
......@@ -870,7 +871,7 @@ function testHtmlCorrectorFilter() {
format_string('HTML corrector -- Existing cdata section @pattern_name properly escaped', array('@pattern_name' => '/*<![CDATA[*/'))
);
$filtered_data = _filter_htmlcorrector('<p><style>
$filtered_data = Html::normalize('<p><style>
<!--/*--><![CDATA[/* ><!--*/
/* Styling */
body {color:red}
......@@ -889,7 +890,7 @@ function testHtmlCorrectorFilter() {
format_string('HTML corrector -- Existing cdata section @pattern_name properly escaped', array('@pattern_name' => '<!--/*--><![CDATA[/* ><!--*/'))
);
$filtered_data = _filter_htmlcorrector('<p><script>
$filtered_data = Html::normalize('<p><script>
<!--//--><![CDATA[// ><!--
alert("test");
//--><!]]>
......@@ -906,7 +907,7 @@ function testHtmlCorrectorFilter() {
format_string('HTML corrector -- Existing cdata section @pattern_name properly escaped', array('@pattern_name' => '<!--//--><![CDATA[// ><!--'))
);
$filtered_data = _filter_htmlcorrector('<p><script>
$filtered_data = Html::normalize('<p><script>
// <![CDATA[
alert("test");
// ]]>
......
......@@ -7,6 +7,7 @@
namespace Drupal\system\Tests\Common;
use Drupal\Component\Utility\Html;
use Drupal\simpletest\DrupalUnitTestBase;
/**
......@@ -616,7 +617,7 @@ function testDrupalRenderChildrenPostRenderCache() {
),
);
$dom = filter_dom_load($cached_element['#markup']);
$dom = Html::load($cached_element['#markup']);
$xpath = new \DOMXPath($dom);
$parent = $xpath->query('//details[@class="form-wrapper" and @open="open"]/summary[@role="button" and @aria-expanded and text()="Parent"]')->length;
$child = $xpath->query('//details[@class="form-wrapper" and @open="open"]/div[@class="details-wrapper"]/details[@class="form-wrapper" and @open="open"]/summary[@role="button" and @aria-expanded and text()="Child"]')->length;
......@@ -699,7 +700,7 @@ function testDrupalRenderChildrenPostRenderCache() {
),
);
$dom = filter_dom_load($cached_parent_element['#markup']);
$dom = Html::load($cached_parent_element['#markup']);
$xpath = new \DOMXPath($dom);
$parent = $xpath->query('//details[@class="form-wrapper" and @open="open"]/summary[@role="button" and @aria-expanded and text()="Parent"]')->length;
$child = $xpath->query('//details[@class="form-wrapper" and @open="open"]/div[@class="details-wrapper"]/details[@class="form-wrapper" and @open="open"]/summary[@role="button" and @aria-expanded and text()="Child"]')->length;
......@@ -724,7 +725,7 @@ function testDrupalRenderChildrenPostRenderCache() {