2

我希望在 php 中创建一个非常简单、非常基本的嵌套目录,它可以获取所有 h1-6 并适当地缩进。这意味着如果我有类似的东西:

<h1>content</h1>
<h2>more content</h2>

我应该得到:

content
    more content.

我知道创建缩进的是css,这很好,但是如何创建一个目录,其中包含指向页面内容的工作链接?

显然很难掌握我的要求......

我要求一个读取 html 文档并提取所有 h1-6 并制作目录的函数。

4

3 回答 3

3

为此,您只需在 HTML 代码中搜索标签。

我写了两个函数(PHP 5.4.x)。

第一个返回一个数组,其中包含目录的数据。数据只是它自己的标题、标签的 id(如果你想使用锚点)和内容的子表。

function get_headlines($html, $depth = 1)
{
    if($depth > 7)
        return [];

    $headlines = explode('<h' . $depth, $html);

    unset($headlines[0]);       // contains only text before the first headline

    if(count($headlines) == 0)
        return [];

    $toc = [];      // will contain the (sub-) toc

    foreach($headlines as $headline)
    {
        list($hl_info, $temp) = explode('>', $headline, 2);
        // $hl_info contains attributes of <hi ... > like the id.
        list($hl_text, $sub_content) = explode('</h' . $depth . '>', $temp, 2);
        // $hl contains the headline
        // $sub_content contains maybe other <hi>-tags
        $id = '';
        if(strlen($hl_info) > 0 && ($id_tag_pos = stripos($hl_info,'id')) !== false)
        {
            $id_start_pos = stripos($hl_info, '"', $id_tag_pos);
            $id_end_pos = stripos($hl_info, '"', $id_start_pos);
            $id = substr($hl_info, $id_start_pos, $id_end_pos-$id_start_pos);
        }

        $toc[] = [  'id' => $id,
                    'text' => $hl_text,
                    'sub_toc' => get_headlines($sub_content, $depth + 1)
                ];

    }

    return $toc;
}

第二个返回一个字符串,它用 HTML 格式化 toc。

function print_toc($toc, $link_to_htmlpage = '', $depth = 1)
{
    if(count($toc) == 0)
        return '';

    $toc_str = '';

    if($depth == 1)
        $toc_str .= '<h1>Table of Content</h1>';

    foreach($toc as $headline)
    {
        $toc_str .= '<p class="headline' . $depth . '">';
        if($headline['id'] != '')
            $toc_str .= '<a href="' . $link_to_htmlpage . '#' . $headline['id'] . '">';

        $toc_str .= $headline['text'];
        $toc_str .= ($headline['id'] != '') ? '</a>' : '';
        $toc_str .= '</p>';

        $toc_str .= print_toc($headline['sub_toc'], $link_to_htmlpage, $depth+1);
    }

    return $toc_str;
}

这两个功能都远非完美,但它们在我的测试中运行良好。随意改进它们。

注意:get_headlines不是解析器,因此它不适用于损坏的 HTML 代码,只会崩溃。它也只适用于小写<hi>标签。

于 2014-05-26T02:57:08.727 回答
2

我使用了这个包,它使用起来非常简单直接。

https://github.com/caseyamcl/toc

通过 Composer 安装,在您的 composer.json 文件中包含以下内容:

{
    "require": {
        "caseyamcl/toc": "^3.0",
    }
}

或者,将 src 文件夹放入您的应用程序并使用 PSR-4 自动加载器来包含文件。

用法 这个包包含两个主要的类:

TOC\MarkupFixer:将 id 锚属性添加到还没有任何 H1...H6 标记(您可以指定在运行时使用哪些标头标记级别) TOC\TocGenerator:从 HTML 标记生成目录基本示例:

$myHtmlContent = <<<END
    <h1>This is a header tag with no anchor id</h1>
    <p>Lorum ipsum doler sit amet</p>
    <h2 id='foo'>This is a header tag with an anchor id</h2>
    <p>Stuff here</p>
    <h3 id='bar'>This is a header tag with an anchor id</h3>
END;

$markupFixer  = new TOC\MarkupFixer();
$tocGenerator = new TOC\TocGenerator();

// This ensures that all header tags have `id` attributes so they can be used as anchor links
$htmlOut  = "<div class='content'>" . $markupFixer->fix($myHtmlContent) . "</div>";

//This generates the Table of Contents in HTML
$htmlOut .= "<div class='toc'>" . $tocGenerator->getHtmlMenu($myHtmlContent) . "</div>";

 echo $htmlOut;

这会产生以下输出:

<div class='content'>
    <h1 id="this-is-a-header-tag-with-no-anchor-id">This is a header tag with no anchor id</h1>
    <p>Lorum ipsum doler sit amet</p>
    <h2 id="foo">This is a header tag with an anchor id</h2>
    <p>Stuff here</p>
    <h3 id="bar">This is a header tag with an anchor id</h3>
</div>
<div class='toc'>
    <ul>
        <li class="first last">
        <span></span>
            <ul class="menu_level_1">
                <li class="first last">
                    <a href="#foo">This is a header tag with an anchor id</a>
                    <ul class="menu_level_2">
                        <li class="first last">
                            <a href="#bar">This is a header tag with an anchor id</a>
                        </li>
                    </ul>
                </li>
            </ul>
        </li>
    </ul>
</div>
于 2021-10-10T11:09:40.947 回答
-1

此函数仅针对 h2 标签返回带有附加目录的字符串。100% 测试代码。

函数目录($str){

        $html = preg_replace('/]+\>/i', '$0

在本文中

', $str, 1); // 内容中第一张图片之后的目录 $doc = 新的 DOMDocument(); $doc->loadHTML($html); // 创建文档片段 $frag = $doc->createDocumentFragment(); // 创建初始列表 $frag->appendChild($doc->createElement('ul')); $head = &$frag->firstChild; $xpath = 新 DOMXPath($doc); $最后 = 1; // 获取所有 H1, H2, ..., H6 元素 $tagChek = 数组(); foreach ($xpath->query('//*[self::h2]') as $headline) { // 获取当前标题的级别 sscanf($headline->tagName, 'h%u', $curr); array_push($tagChek,$headline->tagName); // 必要时移动头部参考 if ($curr parentNode->parentNode; } } elseif ($curr > $last && $head->lastChild) { // 向下移动并创建新列表 for ($i=$last; $ilastChild->appendChild($doc->createElement('ul')); $head = &$head->lastChild->lastChild; } } $last = $curr; // 添加列表项 $li = $doc->createElement('li'); $head->appendChild($li); $a = $doc->createElement('a', $headline->textContent); $head->lastChild->appendChild($a); // 构建标识 $levels = 数组(); $tmp = &$头; // 向上遍历子树到该子树的分片根节点 而 (!is_null($tmp) && $tmp != $frag) { $levels[] = $tmp->childNodes->length; $tmp = &$tmp->parentNode->parentNode; } $id = 'sect'.implode('.', array_reverse($levels)); // 设置目的地 $a->setAttribute('href', '#'.$id); // 给标题添加锚点 $a = $doc->createElement('a'); $a->setAttribute('name', $id); $a->setAttribute('id', $id); $headline->insertBefore($a, $headline->firstChild); } // 回声 $frag; // 将片段附加到文档 if(!empty($tagChek)): $doc->getElementsByTagName('section')->item(0)->appendChild($frag); 返回 $doc->saveHTML(); 别的: 返回 $str; 万一; }
于 2019-11-25T11:20:12.350 回答