2017-05-04 105 views
1

我试图解析一个HTML字符串,并在任何p标签周围添加一个CDATA标签,因此<p>something</p>最终将会是<p><!CDATA[<p>blah</p>]]</p>。这做什么,我想在这方面:DOMDocument和UL tages

$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标签,我需要做那些同样的事情;他们需要在p标记内被CDATA包围,如<p><!CDATA[<ul>blah</ul>]]</p>

我希望我可以去通过串第一,在任何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> 
+0

我对CDATA标签不太熟悉,但是在我看来,就像你对它们有一个太多的右括号(''')。 – freginold

+0

你的意思是你可能在'p'内有'ul'标签? – revo

回答

0

首先关闭所有的,你想用HTML混合XML的概念,为<![CDATA[]]>是不是一个有效的HTML结构。所以,我认为最好将所有内容都视为XML。但是,这要求您的HTML片段必须是有效的XML。

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

然后,我们首先循环访问现有的<p>元素,当然,因为否则我们会循环遍历我们添加的<p>元素。之后,我们循环访问现有的<ul>元素。如你所见,DOMElement->nodeValuewill 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