3 Stimmen

Erstellen eines Inhaltsverzeichnisses in php

Ich bin auf der Suche nach einem sehr einfachen, sehr grundlegenden verschachtelten Inhaltsverzeichnis in php zu erstellen, die alle h1-6 bekommt und Dinge entsprechend einrücken. Dies bedeutet, dass, wenn ich etwas wie haben:

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

Ich sollte es bekommen:

content
    more content.

Ich weiß, dass die Einzüge mit CSS erstellt werden, das ist in Ordnung, aber wie erstelle ich ein Inhaltsverzeichnis mit funktionierenden Links zu den Inhalten auf der Seite?

offenbar Es ist schwer zu begreifen, worum ich bitte...

Ich bitte um eine Funktion, die ein html-Dokument liest und alle h1-6 herauszieht und ein Inhaltsverzeichnis erstellt.

6voto

Yuseferi Punkte 6592

Ich habe dieses Paket benutzt, es ist ziemlich einfach und unkompliziert zu benutzen.

https://github.com/caseyamcl/toc

Installieren Sie über Composer, indem Sie Folgendes in Ihre composer.json-Datei aufnehmen:

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

Oder Sie legen den src-Ordner in Ihrer Anwendung ab und verwenden einen PSR-4-Autoloader, um die Dateien einzubinden.

Verwendung Dieses Paket enthält zwei Hauptklassen:

TOC \MarkupFixer : Fügt id-Ankerattribute zu allen H1...H6-Tags hinzu, die noch keine haben (Sie können zur Laufzeit angeben, welche Kopfzeilenebenen verwendet werden sollen) TOC \TocGenerator : Erzeugt ein Inhaltsverzeichnis aus HTML-Markup Einfaches Beispiel:

$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;

Das Ergebnis ist die folgende Ausgabe:

<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>

2voto

AbcAeffchen Punkte 13534

Dazu müssen Sie nur nach den Tags im HTML-Code suchen.

Ich habe zwei Funktionen geschrieben (PHP 5.4.x).

Die erste gibt ein Array zurück, das die Daten des Inhaltsverzeichnisses enthält. Die Daten sind nur die Überschrift selbst, die ID des Tags (wenn Sie Anker verwenden möchten) und eine Untertabelle des Inhalts.

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;
}

Die zweite gibt eine Zeichenkette zurück, die das Toc mit HTML formatiert.

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;
}

Beide Funktionen sind weit davon entfernt, perfekt zu sein, aber in meinen Tests haben sie gut funktioniert. Sie können sie gerne verbessern.

Hinweis: get_headlines ist kein Parser, d.h. er funktioniert nicht bei kaputtem HTML-Code und stürzt einfach ab. Es funktioniert auch nur mit Kleinbuchstaben <hi> -tags.

-1voto

user1432181 Punkte 464

Wie wäre es damit (obwohl es nur eine H-Stufe kann) ...

function getTOC(string $html, int $level=1) {
    $toc="";
    $x=0;
    $n=0;
    $html1="";

    $safety=1000;
    while ( $x>-1 and $safety-->0 ) {

        $html0=strtolower($html);
        $x=strpos($html0, "<h$level");

        if ( $x>-1 ) {
            $y=strpos($html0, "</h$level>");
            $part=strip_tags(substr($html, $x, $y-$x));

            $toc  .="<a href='#head$n'>$part</a>\n";
            $html1.=substr($html,0,$x)."<a name='head$n'></a>".substr($html, $x, $y-$x+5)."\n";
            $html=substr($html, $y+5);
            $n++;
        }

    }
    $html1.=$html;
    $html=$toc."\n<HR>\n".$html1;
    return $html;
}

Dadurch wird eine grundlegende Liste von Links erstellt

$html="<html><body>";
$html.="<h1>Heading 1a</h1>One Two Three";
$html.="<h2>heading 2a</h2>Four Five Six";
$html.="<h1 class='something'>Heading 1b</h1>Seven Eight Nine";
$html.="<h2>heading 2b</h2>Ten Eleven Twelve";
$html.="</body></html>";

echo getTOC($html, 1);

gibt...

<a href='#head0'>Heading 1a</a>
<a href='#head1'>Heading 1b</a>

<HR>
<html><body><a name='head0'></a><h1>Heading 1a</h1>
One Two Three<h2>heading 2a</h2>Four Five Six<a name='head1'></a><h1 
class='something'>Heading 1b</h1>
Seven Eight Nine<h2>heading 2b</h2>Ten Eleven Twelve</body></html>

Siehe https://onlinephp.io/c/fceb0 für ein laufendes Beispiel

-2voto

ashu sharma Punkte 1

Diese Funktion gibt den String mit angehängtem Inhaltsverzeichnis nur für h2-Tags zurück. 100% getesteter Code.

function toc($str){

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

In This Article

', $str, 1); //toc just after first image in content

        $doc = new DOMDocument();
        $doc->loadHTML($html);

        // create document fragment
        $frag = $doc->createDocumentFragment();
        // create initial list
        $frag->appendChild($doc->createElement('ul'));
        $head = &$frag->firstChild;
        $xpath = new DOMXPath($doc);
        $last = 1;

        // get all H1, H2, …, H6 elements
        $tagChek = array();
        foreach ($xpath->query('//\*\[self::h2\]') as $headline) {
            // get level of current headline
            sscanf($headline->tagName, 'h%u', $curr);
            array\_push($tagChek,$headline->tagName);

            // move head reference if necessary
            if ($curr parentNode->parentNode;
                }
            } elseif ($curr > $last && $head->lastChild) {
                // move downwards and create new lists
                for ($i=$last; $ilastChild->appendChild($doc->createElement('ul'));
                    $head = &$head->lastChild->lastChild;
                }
            }
            $last = $curr;

            // add list item
            $li = $doc->createElement('li');
            $head->appendChild($li);
            $a = $doc->createElement('a', $headline->textContent);
            $head->lastChild->appendChild($a);

            // build ID
            $levels = array();
            $tmp = &$head;
            // walk subtree up to fragment root node of this subtree
            while (!is\_null($tmp) && $tmp != $frag) {
                $levels\[\] = $tmp->childNodes->length;
                $tmp = &$tmp->parentNode->parentNode;
            }
            $id = 'sect'.implode('.', array\_reverse($levels));
            // set destination
            $a->setAttribute('href', '#'.$id);
            // add anchor to headline
            $a = $doc->createElement('a');
            $a->setAttribute('name', $id);
            $a->setAttribute('id', $id);
            $headline->insertBefore($a, $headline->firstChild);
        }
       // echo $frag;
        // append fragment to document
        if(!empty($tagChek)):
            $doc->getElementsByTagName('section')->item(0)->appendChild($frag);
            return $doc->saveHTML();
        else:
            return $str;    
        endif;

    }

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X