【问题标题】:DOMDocument and UL tagesDOMDocument 和 UL 标签
【发布时间】:2017-05-04 14:48:03
【问题描述】:

伙计们,我正在尝试解析一个 HTML 字符串并在任何 p 标记周围添加一个 CDATA 标记,因此 <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 标签内,例如&lt;p&gt;&lt;!CDATA[&lt;ul&gt;blah&lt;/ul&gt;]]&lt;/p&gt;

我希望我可以先遍历字符串并在任何 ul 前面添加一个 p 标签,然后在第二遍使用上述相同的标签来获得所有 p 标签在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>

【问题讨论】:

  • 我对 CDATA 标签不太熟悉,但在我看来,您的右括号太多了 (])。
  • 你的意思是你可能在p中有一些ul标签?

标签: php html domdocument


【解决方案1】:

首先,您试图将 XML 概念与 HTML 混合,因为&lt;![CDATA[]]&gt; 不是有效的 HTML 结构。因此,我认为最好将所有内容都视为 XML。但是,这要求您的 HTML 片段必须是有效的 XML。

然后,由于您的 HTML 片段没有根元素,我们使用DOMDocumentFragment(通过DOMDocument::createDocumentFragment)来导入无根片段。

然后,我们首先循环遍历现有的&lt;p&gt; 元素,当然,否则我们也会循环遍历我们添加的&lt;p&gt; 元素。然后我们遍历现有的&lt;ul&gt; 元素。

如您所见,DOMElement-&gt;nodeValuewill merely give you the textContent of a node。因此,我们改为使用DOMDocument::saveXML( DOMNode $node ) 将 XML 字符串插入 CDATA 部分。

最后,我们将 CDATA 部分包装在新创建的 &lt;p&gt; 元素中。

总而言之,这就是您获得所需输出的方式:

$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

【讨论】:

    猜你喜欢
    • 2014-09-03
    • 1970-01-01
    • 2018-10-23
    • 1970-01-01
    • 2015-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多