伙计们,我正在尝试解析HTML字符串并在CDATA
个标记周围添加p
标记,因此<p>something</p>
最终会成为<p><!CDATA[<p>blah</p>]]</p>
。这就是我在这方面所需要的:
$html_str = '<p><strong>blah blah blah</strong></p><ul><li>blah blah blah</li><li>blah blah blah</li><li>blah blah blah</li></ul><p>blah blah blah</p>';
$domdoc = new DOMDocument();
$domdoc->loadHTML($html_str);
foreach( $domdoc->getElementsByTagName("p") as $pnode ) {
$cdata = $domdoc->createCDATASection('<p>'. $pnode->nodeValue .'</p>');
$pnode->replaceChild($cdata, $pnode->childNodes->item(0));
}
echo $domdoc->saveXML();
问题是字符串中有一些ul
标签不在p
标签内,我需要对它们做同样的事情;它们需要在CDATA
标记中被p
包围,例如<p><!CDATA[<ul>blah</ul>]]</p>
。
我希望我可以先浏览字符串并在任何p
前添加ul
标记,然后在第二遍中使用相同的内容来获取所有p
1}}标记位于CDATA
内,例如:
$html_str = '<p><strong>blah blah blah</strong></p><ul><li>blah blah blah</li><li>blah blah blah</li><li>blah blah blah</li></ul><p>blah blah blah</p>';
$domdoc = new DOMDocument();
$domdoc->loadHTML($html_str);
foreach( $domdoc->getElementsByTagName("ul") as $ulnode ) {
$cdata = $domdoc->createElement("p",$ulnode->nodeValue);
$domdoc->replaceChild($cdata,$ulnode);
}
foreach( $domdoc->getElementsByTagName("p") as $pnode ) {
$cdata = $domdoc->createCDATASection('<p>'. $pnode->nodeValue .'</p>');
$pnode->replaceChild($cdata, $pnode->childNodes->item(0));
}
echo $domdoc->saveXML();
显然这不起作用,我最后只得到li
项的内容。我可以不做那样的2次通过,还是因为ul
是有孩子或其他什么的父母?
我最终想要的是:
<p><!CDATA[<p><strong>blah blah blah</strong></p>]]></p>
<p><!CDATA[<ul><li>blah blah blah</li><li>blah blah blah</li><li>blah blah blah</li></ul>]]></p>
<p><!CDATA[<p>blah blah blah</p>]]></p>
答案 0 :(得分:0)
首先,您尝试将XML概念与HTML混合,因为<![CDATA[]]>
不是有效的HTML构造。因此,我认为将所有内容都视为XML是最好的。但是,这要求您的HTML片段必须是有效的XML。
然后,由于您的HTML片段没有根元素,我们使用DOMDocumentFragment
(通过DOMDocument::createDocumentFragment
)导入无根片段。
然后,我们首先遍历现有的<p>
元素,因为否则我们将遍历我们添加的<p>
元素。然后我们遍历现有的<ul>
元素。
正如您所注意到的,DOMElement->nodeValue
will merely give you the textContent
of a node。因此,我们使用DOMDocument::saveXML( DOMNode $node )
将XML字符串插入CDATA部分。
最后,我们将CDATA部分包装在新创建的<p>
元素中。
要将它全部包装起来,这就是获得所需输出的方法:
$html_str = '<p><strong>blah blah blah</strong></p><ul><li>blah blah blah</li><li>blah blah blah</li><li>blah blah blah</li></ul><p>blah blah blah</p>';
$domdoc = new DOMDocument();
$domfrag = $domdoc->createDocumentFragment();
$domfrag->appendXML($html_str);
$domdoc->appendChild($domfrag);
foreach($domdoc->getElementsByTagName("p") as $pnode) {
$cdata = $domdoc->createCDATASection($domdoc->saveXML($pnode));
$newPnode = $domdoc->createElement("p");
$newPnode->appendChild($cdata);
$pnode->parentNode->replaceChild($newPnode, $pnode);
}
foreach($domdoc->getElementsByTagName("ul") as $ulnode) {
$cdata = $domdoc->createCDATASection($domdoc->saveXML($ulnode));
$newPnode = $domdoc->createElement("p");
$newPnode->appendChild($cdata);
$ulnode->parentNode->replaceChild($newPnode, $ulnode);
}
/**
* unfortunately, LIBXML_NOXMLDECL is not supported
* so $domdoc->saveXML( null, LIBXML_NOXMLDECL ) does not work
* @see https://bugs.php.net/bug.php?id=50989
*/
echo $domdoc->saveXML();
/**
* so, to drop the <?xml declaration line, you could do the following:
*/
foreach($domdoc->childNodes as $node) {
echo $domdoc->saveXML($node) . PHP_EOL; // PHP_EOL is optional
}