2

私は、すべてのh1-6を取得し、物事を適切にインデントする、非常に単純で非常に基本的なネストされた目次をphpで作成しようとしています。これは、私が次のようなものを持っている場合を意味します:

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

私は得る必要があります:

content
    more content.

インデントを作成するのはcssになることはわかっていますが、それは問題ありませんが、ページ上のコンテンツへのリンクが機能する目次を作成するにはどうすればよいですか?

どうやら私が求めているものを理解するのは難しいです...

htmlドキュメントを読み取り、h1-6をすべて引き出して目次を作成する関数を求めています。

4

3 に答える 3

3

このためには、HTMLコードでタグを検索するだけです。

2つの関数(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;
}

2つ目は、tocをHTMLでフォーマットする文字列を返します。

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.jsonファイルに以下を含めてComposer経由でインストールします。

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

または、srcフォルダーをアプリケーションにドロップし、PSR-4オートローダーを使用してファイルを含めます。

使用法このパッケージには、2つの主要なクラスが含まれています。

TOC \ MarkupFixer:まだ持っていないH1 ... H6タグにidアンカー属性を追加します(実行時に使用するヘッダータグレベルを指定できます)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%テストされたコード。

関数toc($ str){

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

記事上で

'、$ str、1); //コンテンツの最初の画像の直後にtoc $ doc = new DOMDocument(); $ doc-> loadHTML($ html); //ドキュメントフラグメントを作成します $ frag = $ doc-> createDocumentFragment(); //初期リストを作成します $ frag-> appendChild($ doc-> createElement('ul')); $ head =&$ frag-> firstChild; $ xpath = new DOMXPath($ doc); $ last = 1; //すべてのH1、H2、…、H6要素を取得します $ tagChek = array(); 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); //ビルドID $ classes = array(); $ tmp =&$ head; //サブツリーをこのサブツリーのフラグメントルートノードまでウォークアップします while(!is_null($ tmp)&& $ tmp!= $ frag){ $ classes [] = $ 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を返します。 endif; }
于 2019-11-25T11:20:12.350 に答える