DOMXpath&;PHP:如何包装一堆<;李>;在<;ul>;


DOMXpath & PHP: how to wrap a bunch of <li> inside an <ul>

我有一个html文档,它有这个不太好的标记,没有"ul":

<p>Lorem</p>
<p>Ipsum...</p>
<li class='item'>...</li>
<li class='item'>...</li>
<li class='item'>...</li>
<div>...</div>

我现在正试图"抓取"所有li元素,并将它们封装在一个ul列表中,我想使用PHP和DOMXPath将其放置在同一位置。我设法找到并"删除"li元素:

$elements =  $xpath->query('//li[@class="item"]');
$wrapper = $document->createElement('ul');
foreach($elements as $child) {
    $wrapper->appendChild($child);
}

也许您可以获得第一个<li>parentNode,然后使用insertBefore方法:

$html = <<<HTML
<p>Lorem</p>
<p>Ipsum...</p>
<li class='item'>...</li>
<li class='item'>...</li>
<li class='item'>...</li>
<div>...</div>
HTML;
$doc = new DOMDocument();
$doc->loadHTML($html);
$xpath = new DOMXpath($doc);
$elements = $xpath->query('//li[@class="item"]');
$wrapper = $doc->createElement('ul');
$elements->item(0)->parentNode->insertBefore(
    $wrapper, $elements->item(0)
);
foreach($elements as $child) {
    $wrapper->appendChild($child);
}
echo $doc->saveHTML();

演示

以下是您需要的。您可能需要针对真实的HTML调整XPath查询。

$document = new DOMDocument;
// We don't want to bother with white spaces
$document->preserveWhiteSpace = false;
$html = <<<EOT
<p>Lorem</p>
<p>Ipsum...</p>
<li class='item'>...</li>
<li class='item'>...</li>
<li class='item'>last...</li>
<div>...</div>
EOT;
$document->LoadHtml($html);
$xpath = new DOMXPath($document);
$elements =  $xpath->query('//li[@class="item"]');
// Saves a reference to the Node that is positioned right after our li's
$ref = $xpath->query('//li[@class="item"][last()]')->item(0)->nextSibling;
$wrapper = $document->createElement('ul');
foreach($elements as $child) {
    $wrapper->appendChild($child);
} 
$ref->parentNode->insertBefore($wrapper, $ref);
echo $document->saveHTML();

运行示例:https://repl.it/B3UO/24