2

我有一个后续问题,Jack 已经回答了我的问题: Wrap segments of HTML with divs (and generate table of contents from HTML-tags) with PHP

我一直在尝试为上面的答案添加一些功能,以获得以下结果。

这是我现在的 HTML:

<h3>Subtitle</h3>
<p>This is a paragraph</p>
<p>This is another paragraph</p>
<h3>Another subtile
  <h3>
    <p>Yet another paragraph</p>

这就是我想要实现的目标:

<h3 class="current">Subtitle</h3>
<div class="ac_pane" style="display:block;">
  <p>This is a paragraph</p>
  <p>This is another paragraph</p>
</div>
<h3>Another subtitle</h3>
<div class="ac_pane">
  <p>Yet another paragraph</p>
</div>

我一直在尝试修改上面示例中的代码,但无法弄清楚:

foreach ($d->getElementsByTagName('h3') as $h3) {
    $ac_pane_nodes = array($h3);
    for ($next = $h3->nextSibling; $next && $next->nodeName != 'h3'; $next = $next->nextSibling) {
        $ac_pane_nodes[] = $next;
    }
    $ac_pane = $d->createElement('div');
    $ac_pane->setAttribute('class', 'ac_pane');
    // Here I'm trying to wrap all tags between h3-sets, but am failing!
            $h3->parentNode->appendChild($ac_pane, $h3);
    foreach ($ac_pane_nodes as $node) {
        $ac_pane->appendChild($node);
    }
}

请注意,添加class="current"到第一个 h3 集和添加style="display:block;"到第一个集div.ac_pane是可选的,但非常感谢。

4

1 回答 1

4

根据要求,这是一个工作版本。IMO XSLT 仍然是最适合此类问题的解决方案(将一些 XML 转换为其他 XML,真的),但我不得不承认使用常规代码进行分组要容易得多!

我最终稍微扩展了 DOM API,只是为了insertAfter在 DOMElement 上添加一个实用方法。没有它也可以完成,但它更整洁:

根据评论中的要求,更新为围绕所有标签包装 DIV

<?php

class DOMDocumentExtended extends DOMDocument {
    public function __construct($version = "1.0", $encoding = "UTF-8") {
        parent::__construct($version, $encoding);
        $this->registerNodeClass("DOMElement", "DOMElementExtended");
    }
}

class DOMElementExtended extends DOMElement {
    public function insertAfter($targetNode) {
        if ($targetNode->nextSibling) {
            $targetNode->parentNode->insertBefore($this, $targetNode->nextSibling);
        } else {
            $targetNode->parentNode->appendChild($this);
        }
    }

    public function wrapAround(DOMNodeList $nodeList) {
        while (($node = $nodeList->item(0)) !== NULL) {
            $this->appendChild($node);
        }
    }
}

$doc = new DOMDocumentExtended();
$doc->loadHTML(
    "<h3>Subtitle</h3>
    <p>This is a paragraph</p>
    <p>This is another paragraph</p>
    <h3>Another subtile</h3>
    <p>Yet another paragraph</p>"
);

// Grab a nodelist of all h3 tags
$nodeList = $doc->getElementsByTagName("h3");

// Iterate over each of these h3 nodes
foreach ($nodeList as $index => $h3) {

    // Special handling for first h3
    if ($index === 0) {
        $h3->setAttribute("class", "current");
    }

    // Create a div node that we'll use as our wrapper
    $div = $doc->createElement("div");
    $div->setAttribute("class", "ac_pane");

    // Special handling for first div wrapper
    if ($index === 0) {
        $div->setAttribute("style", "display:block;");
    }

    // Move next siblings of h3 until we hit another h3
    while ($h3->nextSibling && $h3->nextSibling->localName !== "h3") {
        $div->appendChild($h3->nextSibling);
    }

    // Add the div node right after the h3
    $div->insertAfter($h3);
}

// UPDATE: wrap all child nodes of body in a div
$div = $doc->createElement("div");
$body = $doc->getElementsByTagName("body")->item(0);
$div->wrapAround($body->childNodes);
$body->appendChild($div);

echo $doc->saveHTML();

请注意,loadHTML 将添加 doctype、html 和 body 节点。如果需要,可以将它们剥离

于 2012-05-24T14:37:31.480 回答