使用 DOMXPath 清理弃用的 HTML 代码(将嵌套的 <div> 标签转换为 <p> 标签)
Cleaning up deprecated HTML code with DOMXPath (convert nested <div> tags to <p> tags)
我正在尝试将存储在旧 MS Access 数据库中的富文本读入新的 PHP 网络应用程序。清理后的数据将使用 CKEditor 显示给用户,CKEditor 对符合 HTML 代码的解析标准非常严格。但是,存储在 MS Access 中的数据通常格式不正确或使用已弃用的 HTML 代码。
下面是我要清理的数据示例:
<div align="right">Previous claim $ 935.00<div align="right"> This claim ,572.50</div></div>
此数据应该是两行右对齐的文本,但是 MS Access 使用已弃用的 align 属性来设置 <div>
标签的样式style 属性,并且错误地嵌套了它们,而在这种情况下它们应该是顺序的。
为了将此示例数据转换为两行右对齐的文本,并且 CKEditor 将按预期读取和显示(即文本显示为右对齐),我正在尝试替换 <div>
带有 <p>
标签的标签,并注入带有右文本对齐的内联样式属性以替换已弃用的对齐属性。
我正在使用PHP的DOMXPath清理数据,代码如下:
$dom = new DOMDocument();
$dom->loadHTML($dataForCleaning, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$xpath = new DOMXPath($dom);
foreach ($xpath->query('//div[@align]') as $node) {
$alignment = $node->getAttribute('align');
$newNode = $dom->createElement('p');
$newNode->setAttribute("style", "text-align:".$alignment);
$node->parentNode->insertBefore($newNode, $node);
foreach ($node->childNodes as $child) {
$newNode->appendChild($child);
}
$node->parentNode->removeChild($node);
}
我正在使用 insertBefore
代替 appendChild
来尝试保持元素的顺序相同,但这就是导致此嵌套数据示例出现问题的原因。
对于非嵌套 <div>
标签作为要清理的输入数据,清理后的输出 html 是正确的。但是,在这个嵌套的 <div>
示例中,输出最终为:
<p style="text-align:right">Previous claim $ 935.00</p>
请注意,第二行文本 (This claim...) 已被删除,因为它在嵌套 <div>
中作为父项的子项<div>
我不介意生成的 <p>
标签是否保持嵌套,因为 CKEditor 最终会清理这些标签,但我确实需要确保我不会像当前代码那样丢失数据。
在此先感谢您的帮助和指导。
-马克
我更改了一些内容。首先是,我不只是附加现有节点,而是克隆节点并附加副本(在 $newNode->appendChild($child->cloneNode(true));
中),第二件事是当您移动封闭的节点时,我认为XPath 不再指向这个移动的节点。因此,取而代之的是,我在复制子节点时检查是否具有相同的 <div align="right">
节点模式,如果是,我将以新格式创建一个新节点并添加它...
foreach ($xpath->query('//div[@align]') as $node) {
$alignment = $node->getAttribute('align');
$newNode = $dom->createElement('p');
$newNode->setAttribute("style", "text-align:".$alignment);
$node->parentNode->insertBefore($newNode, $node);
foreach ($node->childNodes as $child) {
if ( $child instanceof DOMElement && $child->localName == "div"
&& $child->attributes->getNamedItem("align")->nodeValue == "right" ) {
$subNode = $dom->createElement('p', $child->nodeValue );
$subNode->setAttribute("style", "text-align:".$alignment);
$newNode->appendChild($subNode);
}
else {
$newNode->appendChild($child->cloneNode(true));
}
}
$node->parentNode->removeChild($node);
}
对于您给出的示例,输出的是...
<p style="text-align:right">
Previous claim $ 935.00
<p style="text-align:right"> This claim ,572.50</p>
</p>
我正在尝试将存储在旧 MS Access 数据库中的富文本读入新的 PHP 网络应用程序。清理后的数据将使用 CKEditor 显示给用户,CKEditor 对符合 HTML 代码的解析标准非常严格。但是,存储在 MS Access 中的数据通常格式不正确或使用已弃用的 HTML 代码。
下面是我要清理的数据示例:
<div align="right">Previous claim $ 935.00<div align="right"> This claim ,572.50</div></div>
此数据应该是两行右对齐的文本,但是 MS Access 使用已弃用的 align 属性来设置 <div>
标签的样式style 属性,并且错误地嵌套了它们,而在这种情况下它们应该是顺序的。
为了将此示例数据转换为两行右对齐的文本,并且 CKEditor 将按预期读取和显示(即文本显示为右对齐),我正在尝试替换 <div>
带有 <p>
标签的标签,并注入带有右文本对齐的内联样式属性以替换已弃用的对齐属性。
我正在使用PHP的DOMXPath清理数据,代码如下:
$dom = new DOMDocument();
$dom->loadHTML($dataForCleaning, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$xpath = new DOMXPath($dom);
foreach ($xpath->query('//div[@align]') as $node) {
$alignment = $node->getAttribute('align');
$newNode = $dom->createElement('p');
$newNode->setAttribute("style", "text-align:".$alignment);
$node->parentNode->insertBefore($newNode, $node);
foreach ($node->childNodes as $child) {
$newNode->appendChild($child);
}
$node->parentNode->removeChild($node);
}
我正在使用 insertBefore
代替 appendChild
来尝试保持元素的顺序相同,但这就是导致此嵌套数据示例出现问题的原因。
对于非嵌套 <div>
标签作为要清理的输入数据,清理后的输出 html 是正确的。但是,在这个嵌套的 <div>
示例中,输出最终为:
<p style="text-align:right">Previous claim $ 935.00</p>
请注意,第二行文本 (This claim...) 已被删除,因为它在嵌套 <div>
中作为父项的子项<div>
我不介意生成的 <p>
标签是否保持嵌套,因为 CKEditor 最终会清理这些标签,但我确实需要确保我不会像当前代码那样丢失数据。
在此先感谢您的帮助和指导。 -马克
我更改了一些内容。首先是,我不只是附加现有节点,而是克隆节点并附加副本(在 $newNode->appendChild($child->cloneNode(true));
中),第二件事是当您移动封闭的节点时,我认为XPath 不再指向这个移动的节点。因此,取而代之的是,我在复制子节点时检查是否具有相同的 <div align="right">
节点模式,如果是,我将以新格式创建一个新节点并添加它...
foreach ($xpath->query('//div[@align]') as $node) {
$alignment = $node->getAttribute('align');
$newNode = $dom->createElement('p');
$newNode->setAttribute("style", "text-align:".$alignment);
$node->parentNode->insertBefore($newNode, $node);
foreach ($node->childNodes as $child) {
if ( $child instanceof DOMElement && $child->localName == "div"
&& $child->attributes->getNamedItem("align")->nodeValue == "right" ) {
$subNode = $dom->createElement('p', $child->nodeValue );
$subNode->setAttribute("style", "text-align:".$alignment);
$newNode->appendChild($subNode);
}
else {
$newNode->appendChild($child->cloneNode(true));
}
}
$node->parentNode->removeChild($node);
}
对于您给出的示例,输出的是...
<p style="text-align:right">
Previous claim $ 935.00
<p style="text-align:right"> This claim ,572.50</p>
</p>