将 H3 标签及其下的所有 UL 标签包裹在 div 中
Wrap a H3 tag and all UL tags under it in a div
我的结构是这样的:
<h3><span class="header" id="first_set">My Heading</span></h3>
<ul><li>Text Text Text</li></ul>
<ul><li>Text Text Text</li></ul>
<ul><li>Text Text Text</li></ul>
<h3><span class="header" id="second_set">My Second Heading</span></h3>
<ul><li>Text Text Text</li></ul>
<ul><li>Text Text Text</li></ul>
<ul><li>Text Text Text</li></ul>
<h3><span class="header" id="third_set">My Third Heading</span></h3>
<ul><li>Text Text Text</li></ul>
<ul><li>Text Text Text</li></ul>
<ul><li>Text Text Text</li></ul>
我使用 DOMDocument 从 web-page 中提取了这个。我需要遍历 9000 页,它们都有细微的变化。所以 "Third Heading" 在某些情况下实际上可能是 table 而不是另一个 h3.
我想要准确地做的是将 div 包裹在第二个标题周围,并在找不到更多 </ul>
标签时关闭 div(直到它碰到任何不是 ul 标签)。所以结果会是这样的:
<h3><span class="header" id="first_set">My Heading</span></h3>
<ul><li>Text Text Text</li></ul>
<ul><li>Text Text Text</li></ul>
<ul><li>Text Text Text</li></ul>
<div class="second_heading">
<h3><span class="header" id="second_set">My Second Heading</span></h3>
<ul><li>Text Text Text</li></ul>
<ul><li>Text Text Text</li></ul>
<ul><li>Text Text Text</li></ul>
</div>
<h3><span class="header" id="third_set">My Third Heading</span></h3>
<ul><li>Text Text Text</li></ul>
<ul><li>Text Text Text</li></ul>
<ul><li>Text Text Text</li></ul>
我在考虑 preg_replace
但不确定如何执行 "close div when last closing ul tag is found" 的逻辑。
您可以在使用 DOMDocument
的同时实现这一目标。我假设您有一个名为 $node
的变量,它是您在问题中显示的 HTML 上方的节点。在这种情况下,您可以使用 DOMXPath
找到该元素的所有 child 节点,然后遍历它们直到到达第二个 <h3>
并追加它和所有后续 <ul>
元素到一个新的 <div>
直到你到达第二个 header 之后的第一个非 <ul>
元素:
$div = $doc->createElement('div');
$xpath = new DOMXPath($doc);
$headers = 0;
foreach ($xpath->query('./*', $node) as $child) {
echo $child->nodeName;
switch ($child->nodeName) {
case 'h3':
$headers++;
if ($headers == 2) {
$node->replaceChild($div, $child);
$div->appendChild($child);
}
else if ($headers == 3) {
break 2;
}
break;
case 'ul':
if ($headers == 2) $div->appendChild($child);
break;
default:
// if a non-ul element after the 2nd header, exit the loop
if ($headers == 2) break 2;
break;
}
}
我的结构是这样的:
<h3><span class="header" id="first_set">My Heading</span></h3>
<ul><li>Text Text Text</li></ul>
<ul><li>Text Text Text</li></ul>
<ul><li>Text Text Text</li></ul>
<h3><span class="header" id="second_set">My Second Heading</span></h3>
<ul><li>Text Text Text</li></ul>
<ul><li>Text Text Text</li></ul>
<ul><li>Text Text Text</li></ul>
<h3><span class="header" id="third_set">My Third Heading</span></h3>
<ul><li>Text Text Text</li></ul>
<ul><li>Text Text Text</li></ul>
<ul><li>Text Text Text</li></ul>
我使用 DOMDocument 从 web-page 中提取了这个。我需要遍历 9000 页,它们都有细微的变化。所以 "Third Heading" 在某些情况下实际上可能是 table 而不是另一个 h3.
我想要准确地做的是将 div 包裹在第二个标题周围,并在找不到更多 </ul>
标签时关闭 div(直到它碰到任何不是 ul 标签)。所以结果会是这样的:
<h3><span class="header" id="first_set">My Heading</span></h3>
<ul><li>Text Text Text</li></ul>
<ul><li>Text Text Text</li></ul>
<ul><li>Text Text Text</li></ul>
<div class="second_heading">
<h3><span class="header" id="second_set">My Second Heading</span></h3>
<ul><li>Text Text Text</li></ul>
<ul><li>Text Text Text</li></ul>
<ul><li>Text Text Text</li></ul>
</div>
<h3><span class="header" id="third_set">My Third Heading</span></h3>
<ul><li>Text Text Text</li></ul>
<ul><li>Text Text Text</li></ul>
<ul><li>Text Text Text</li></ul>
我在考虑 preg_replace
但不确定如何执行 "close div when last closing ul tag is found" 的逻辑。
您可以在使用 DOMDocument
的同时实现这一目标。我假设您有一个名为 $node
的变量,它是您在问题中显示的 HTML 上方的节点。在这种情况下,您可以使用 DOMXPath
找到该元素的所有 child 节点,然后遍历它们直到到达第二个 <h3>
并追加它和所有后续 <ul>
元素到一个新的 <div>
直到你到达第二个 header 之后的第一个非 <ul>
元素:
$div = $doc->createElement('div');
$xpath = new DOMXPath($doc);
$headers = 0;
foreach ($xpath->query('./*', $node) as $child) {
echo $child->nodeName;
switch ($child->nodeName) {
case 'h3':
$headers++;
if ($headers == 2) {
$node->replaceChild($div, $child);
$div->appendChild($child);
}
else if ($headers == 3) {
break 2;
}
break;
case 'ul':
if ($headers == 2) $div->appendChild($child);
break;
default:
// if a non-ul element after the 2nd header, exit the loop
if ($headers == 2) break 2;
break;
}
}