2017-05-04 59 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