DOMDocument和UL tages

时间:2017-05-04 14:48:04

标签: php html domdocument

伙计们,我正在尝试解析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>

1 个答案:

答案 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
}

您可以view this example online