Reto: HTML Überschriften Pharsen und Inhaltsverzeichnis erstellen

Hallo,

ich habe einen Text der gegliedert ist mit H1, H2, H3, H4, H5, H6. Hierzu möchte ich ein Inhaltsverzeichnis mit Sprungmarken erstellen. Mein Erster gedanke war mit prematch die h1, h2... aus zu lesen uns ein Array zu erstellen. Das Problem ich muss ja jede Überschrift einzeln Pregmatchen, dh. ich verliere die korrekte Reihenfolge.

Ich kann ich so parsen das ich die Reihenfolge behalte und ggf. noch sagen kann welche Unterüberschrift zu welcher Überschrift gehört?

  1. Du meinst preg_match?

    Das verträgt auch die Suche nach /<[hH][1-6]>(.*)<\/[hH][1-6]>/ als Pattern. Zudem willst Du wohl preg_machtch_all() verwenden:

    <?php
    $pattern = '/<[hH][1-6]>(.*)<\/[hH][1-6]>/';
    
    
    $text = '
    <h1>1) Erste, Erster Ordnung</h1>
    <h2>1.1) Erstens, Erste Zweiter Ordnung</h2>
    <h2>1.2) Erstens, Zweite Zweiter Ordnung</h2>
    
    <h1>2) Zweitens, Erster Ordnung</h1>
    <h2>2.1) Zweitens, Erste Zweiter Ordnung</h2>
    <h2>2.2) Zweitens, Zweite Zweiter Ordnung</h2>
    ';
    
    $foo = preg_match_all( $pattern, $text, $ar, PREG_OFFSET_CAPTURE);
    var_dump($ar);
    print "\n";
    

    Ergebnis:

    array(2) {
      [0] =>
      array(6) {
        [0] =>
        array(2) {
          [0] =>
          string(33) "<h1>1) Erste, Erster Ordnung</h1>"
          [1] =>
          int(1)
        }
        [1] =>
        array(2) {
          [0] =>
          string(44) "<h2>1.1) Erstens, Erste Zweiter Ordnung</h2>"
          [1] =>
          int(35)
        }
        [2] =>
        array(2) {
          [0] =>
          string(45) "<h2>1.2) Erstens, Zweite Zweiter Ordnung</h2>"
          [1] =>
          int(80)
        }
        [3] =>
        array(2) {
          [0] =>
          string(36) "<h1>2) Zweitens, Erster Ordnung</h1>"
          [1] =>
          int(127)
        }
        [4] =>
        array(2) {
          [0] =>
          string(45) "<h2>2.1) Zweitens, Erste Zweiter Ordnung</h2>"
          [1] =>
          int(164)
        }
        [5] =>
        array(2) {
          [0] =>
          string(46) "<h2>2.2) Zweitens, Zweite Zweiter Ordnung</h2>"
          [1] =>
          int(210)
        }
      }
      [1] =>
      array(6) {
        [0] =>
        array(2) {
          [0] =>
          string(24) "1) Erste, Erster Ordnung"
          [1] =>
          int(5)
        }
        [1] =>
        array(2) {
          [0] =>
          string(35) "1.1) Erstens, Erste Zweiter Ordnung"
          [1] =>
          int(39)
        }
        [2] =>
        array(2) {
          [0] =>
          string(36) "1.2) Erstens, Zweite Zweiter Ordnung"
          [1] =>
          int(84)
        }
        [3] =>
        array(2) {
          [0] =>
          string(27) "2) Zweitens, Erster Ordnung"
          [1] =>
          int(131)
        }
        [4] =>
        array(2) {
          [0] =>
          string(36) "2.1) Zweitens, Erste Zweiter Ordnung"
          [1] =>
          int(168)
        }
        [5] =>
        array(2) {
          [0] =>
          string(37) "2.2) Zweitens, Zweite Zweiter Ordnung"
          [1] =>
          int(214)
        }
      }
    }
    
    1. Du kannst auch gleich mit preg_replace() ersetzen. Dazu ist eine Callback-Funktion erforderlich und dass Du die Teile, die erhalten werden sollen, im Pattern so klammerst, dass diese dann im jeweiligen Array für den Treffer erscheinen, der an die callback-Funktion übergeben wird. Diese baut dann das Replacement (Hier mit einem Zähler aus der globalen Variable i) zusammen und gibt es zurück:

      <?php
      $pattern = '/(<[hH][1-6])(>)(.*)(<\/[hH][1-6]>)/';
      
      
      $subject = '
      <h1>1) Erste, Erster Ordnung</h1>
      <h2>1.1) Erstens, Erste Zweiter Ordnung</h2>
      <h2>1.2) Erstens, Zweite Zweiter Ordnung</h2>
      
      <h1>2) Zweitens, Erster Ordnung</h1>
      <h2>2.1) Zweitens, Erste Zweiter Ordnung</h2>
      <h2>2.2) Zweitens, Zweite Zweiter Ordnung</h2>
      ';
      
      
      $foo=preg_replace_callback ( $pattern , 'replFunkt' , $subject , -1 , $count );
      
      $i= 0;
      function replFunkt( $ar ) {
      	
      	    print_r( $ar );
      	    global $i;
      	    $i++;
      		return $ar[1] . ' id="A_' . $i . '"' . $ar[2] . $ar[3] . $ar[4];
      }
      
      print_r ( $foo ); print "\n";
      
      

      Ausgaben:

      Array
      (
          [0] => <h1>1) Erste, Erster Ordnung</h1>
          [1] => <h1
          [2] => >
          [3] => 1) Erste, Erster Ordnung
          [4] => </h1>
      )
      Array
      (
          [0] => <h2>1.1) Erstens, Erste Zweiter Ordnung</h2>
          [1] => <h2
          [2] => >
          [3] => 1.1) Erstens, Erste Zweiter Ordnung
          [4] => </h2>
      )
      Array
      (
          [0] => <h2>1.2) Erstens, Zweite Zweiter Ordnung</h2>
          [1] => <h2
          [2] => >
          [3] => 1.2) Erstens, Zweite Zweiter Ordnung
          [4] => </h2>
      )
      Array
      (
          [0] => <h1>2) Zweitens, Erster Ordnung</h1>
          [1] => <h1
          [2] => >
          [3] => 2) Zweitens, Erster Ordnung
          [4] => </h1>
      )
      Array
      (
          [0] => <h2>2.1) Zweitens, Erste Zweiter Ordnung</h2>
          [1] => <h2
          [2] => >
          [3] => 2.1) Zweitens, Erste Zweiter Ordnung
          [4] => </h2>
      )
      Array
      (
          [0] => <h2>2.2) Zweitens, Zweite Zweiter Ordnung</h2>
          [1] => <h2
          [2] => >
          [3] => 2.2) Zweitens, Zweite Zweiter Ordnung
          [4] => </h2>
      )
      
      <h1 id="A_1">1) Erste, Erster Ordnung</h1>
      <h2 id="A_2">1.1) Erstens, Erste Zweiter Ordnung</h2>
      <h2 id="A_3">1.2) Erstens, Zweite Zweiter Ordnung</h2>
      
      <h1 id="A_4">2) Zweitens, Erster Ordnung</h1>
      <h2 id="A_5">2.1) Zweitens, Erste Zweiter Ordnung</h2>
      <h2 id="A_6">2.2) Zweitens, Zweite Zweiter Ordnung</h2>
      
      

      Es lohnt sich reguläre Ausdrücke zu lernen.

      Und wenn wir schon dabei sind: Auch das Menü kann gleichzeitig automatisch erzeugt werden:

      <?php
      $pattern = '/(<[hH][1-6])(>)(.*)(<\/[hH][1-6]>)/';
      
      
      $subject = '
      <h1>1) Erste, Erster Ordnung</h1>
      <h2>1.1) Erstens, Erste Zweiter Ordnung</h2>
      <h2>1.2) Erstens, Zweite Zweiter Ordnung</h2>
      
      <h1>2) Zweitens, Erster Ordnung</h1>
      <h2>2.1) Zweitens, Erste Zweiter Ordnung</h2>
      <h2>2.2) Zweitens, Zweite Zweiter Ordnung</h2>
      ';
      
      
      $i= 0;
      $menue='<nav><ul>';
      $foo=preg_replace_callback ( $pattern , 'replFunkt' , $subject , -1 , $count );
      $menue .= '</ul></nav>';
      
      
      function replFunkt($ar) {
      	
      	    print_r($ar);
      	    global $i;
      	    $i++;
      	    global $menue;
      	    $menue .= '<li><a href="#A_' . $i . '">' . $ar[3] . '</a></li>';
      	    
      		return $ar[1] . ' id="A_' . $i . '"' . $ar[2] . $ar[3] . $ar[4];
      		
      }
      
      print_r ( $foo ); print "\n";
      print_r ( $menue ); print "\n";
      
      <nav><ul><li><a href="#A_1">1) Erste, Erster Ordnung</a></li><li><a href="#A_2">1.1) Erstens, Erste Zweiter Ordnung</a></li><li><a href="#A_3">1.2) Erstens, Zweite Zweiter Ordnung</a></li><li><a href="#A_4">2) Zweitens, Erster Ordnung</a></li><li><a href="#A_5">2.1) Zweitens, Erste Zweiter Ordnung</a></li><li><a href="#A_6">2.2) Zweitens, Zweite Zweiter Ordnung</a></li></ul></nav>
      
    2. Hammer, vielen Dank.

      Reto

      1. Bitte.

        Falls noch jemand so ein "Inhaltsverzeichnis einfügen-Tool für Webseiten" braucht.

    3. @@Regina Schaukrug

      Du meinst preg_match?

      Nein. Mit regulären Ausdrücken das DOM zu parsen ist wohl nie eine gute Idee.

      LLAP 🖖

      --
      „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
  2. Hello,

    Ich kann ich so parsen das ich die Reihenfolge behalte und ggf. noch sagen kann welche Unterüberschrift zu welcher Überschrift gehört?

    Das machst Du bei PHP am besten mittels XPath aus der DOM-Klassensammlung.

    Es benötigt nur wenige Zeilen, um dann alle gewünschten HTML-Elemente in sinnvoller Reihenfolge sortiert in einem Array wiederzufinden.

    Eventuell reicht auch schon ::xpath() aus der SimpleXML-Element-Klasse

    Ich mühe mich gerade mit der Datenübernahme nebst Programmneuinstallation von meinem alten PC auf einen weniger alten ab. Wenn ich damit einigermaßen durch bin, kann ich Dir gerne weiterhelfen.
    
    
    
    
    
      
    Liebe Grüße  
    Tom S.   
    
    
    -- 
     Es gibt nichts Gutes, außer man tut es!     
     Das Leben selbst ist der Sinn.  
    
    
    
    
    
    
    
    1. Hallo Tom,

      danke für die Hilfe. Es waren jetzt 40 Zeilen Code für das perfekte Inhaltsverzeichnis mit Sprungmarken.

      Danke Reto

      1. Hello,

        prima, dass es geklappt hat!
        Zeigst Du uns deine Lösung noch?

        Wenn sie wiederverwertbar ist, hast Du ja auf jeden Fall etwas davon für deine Sammlung und Andere könnten dann auch davon profitieren :-)

        Liebe Grüße
        Tom S.

        --
        Es gibt nichts Gutes, außer man tut es!
        Das Leben selbst ist der Sinn.
    2. Das machst Du bei PHP am besten mittels XPath aus der DOM-Klassensammlung.

      Wenn ich damit einigermaßen durch bin, kann ich Dir gerne weiterhelfen.

      Ich hab für Dich schon mal angefangen:

      <?php
      
      $html='<!DOCTYPE html>
      <html lang="de">
        <head>
          <meta charset="utf-8">
          <meta http-equiv="X-UA-Compatible" content="IE=Edge">
          <meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no">
        </head>
        <body>
      	<h1>Hallo Welt!</h1>
      	<p>Lorem ipsum
      	<h2>Jaja</h2>
      	<p>Lorem ipsum
      	<p>Lorem ipsum
      	<h2>Soso</h2>
      	<p>Lorem ipsum
      	<p>Lorem ipsum	
        </body>
      </html>';
      
      $doc = new DOMDocument();
      $doc -> loadHTML( $html );
      
      foreach ( $doc -> getElementsByTagName( '*' ) as $node ) {
          $path = $node -> getNodePath();
          $ar = array_reverse( explode( '/', $path ) );
          $tagName = array_shift( $ar );
          if ( preg_match( '/[Hh][1-6]/', $tagName ) ) {
              echo $node -> textContent . "\n";
          }
      }
      
  3. hallo

    ich habe einen Text der gegliedert ist mit H1, H2, H3, H4, H5, H6. Hierzu möchte ich ein Inhaltsverzeichnis mit Sprungmarken erstellen.

    Dazu ist JS optimal.

    Beispiel für https://beat-stoecklin.ch/pub/webdesign.html

    	_.toc=addToc( _.body.querySelectorAll("h1,h2,h3") );
    
    ///
    
    function addToc( h, i, toc ){
    	toc='';
    	for(i=0; i<h.length; i++){
    		h[i].id = "h"+i;
    		toc += '<a class="'+h[i].nodeName+'" href="#h'+i+'">'+h[i].innerText+'</a>';
    	}
    	return toc;
    }
    
    --
    Neu im Forum! Signaturen kann man ausblenden!
    1. Hallo

      Dazu ist JS optimal.

      Das sehe ich anders. Jedenfalls wenn das Skript im Browser ausgeführt werden soll, denn man kann sich nicht darauf verlassen, dass JS dort immer zur Verfügung steht. Vielleicht wurde JavaScript ausgeschaltet. Oder das jeweilige Skript konnte wegen schlechtem Empfang nicht vollständig geladen werden. In solchen Fällen gibt es dann kein Inhaltsverzeichnis, was die Benutzbarkeit der Seite stark einschränkt. Welcher Benutzer will schon bis herab zum Seitenende scrollen, nur um sich einen Überblick über den Inhalt zu verschaffen?

      Ein Inhaltsverzeichnis mit Links zu den jeweiligen Abschnitten einer Seite gehört für mich zu den Features, die auch dann verfügbar sein sollten, wenn JavaScript es nicht ist.


      Trotzdem noch ein paar Anmerkungen:

      	_.toc=addToc( _.body.querySelectorAll("h1,h2,h3") );
      
      ///
      
      function addToc( h, i, toc ){
      	toc='';
      	for(i=0; i<h.length; i++){
      		h[i].id = "h"+i;
      		toc += '<a class="'+h[i].nodeName+'" href="#h'+i+'">'+h[i].innerText+'</a>';
      	}
      	return toc;
      }
      

      Warum legst du hier nicht lokale Variablen an? Unabhängig davon, ob für den zweiten und dritten Parameter Werte übergeben wurden, bindest du im Körper der Funktion neue Werte an die Bezeichner. Das verschleiert den eigentlichen Zweck der Variablen. Daran sollte sich niemand ein Beispiel nehmen.

      Aus semantischen Gründen würde ich auf Elementen auch lieber die Eigenschaft tagName statt der Eigenschaft nodeName referenzieren, aber das schenkt sich ansonsten nichts. Bei innerText sollte man sich hingegen gut überlegen, ob man das wirklich will. Hier ist in der Regel die Eigenschaft textContent die bessere Wahl, unter anderem, weil innerText einen Reflow auslösen kann. Das heißt, abhängig vom jeweiligen Browser, wird bei jedem Zugriff auf die Eigenschaft ein Teil der Seite neu gerendert.

      Bei der Entwicklung würde ich darüber hinaus Templateliterale verwenden, statt die Zeichenketten mit dem Plusoperator zu verbinden. Vor der Auslieferung an den Client kann man den Code dann mit einem Transpiler wie Babel in ein kompatibleres Format übersetzen. So kann man die Vorteile moderner Syntax nutzen, ohne damit Nutzer auszuschließen.

      Viele Grüße,

      Orlok

      --
      „Dance like it hurts.
      Make love like you need money.
      Work when people are watching.“ — Dogbert
      1. hallo

        Dazu ist JS optimal.

        Das sehe ich anders.

        Ja klar. Energie kostet ja nichts!

        --
        Neu im Forum! Signaturen kann man ausblenden!
        1. Hallo beatovich,

          Dazu ist JS optimal.

          Das sehe ich anders.

          Ja klar. Energie kostet ja nichts!

          Die Programmausführung kostet Energie. Egal in welcher Sprache. Auf dem Server wird es ggf. einmal gemacht, dann die Seite gespeichert und tausende von Besuchern können sie abrufen, ohne auch nur ein Fitzelchen[1] Energie ungewünschterweise in Wärmeenergie umzuwandeln.

          Bis demnächst
          Matthias

          --
          Rosen sind rot.

          1. steht sogar im Duden. ↩︎

          1. hallo

            Hallo beatovich,

            Dazu ist JS optimal.

            Das sehe ich anders.

            Ja klar. Energie kostet ja nichts!

            Die Programmausführung kostet Energie. Egal in welcher Sprache. Auf dem Server wird es ggf. einmal gemacht

            Wunschdenken. Normalerweise werden Seiten neu konstruiert, sobald sich nur ein Anlass dazu ergibt. Und gerade wegen dieser Anhängigkeiten erweist sich server konstruierte fixfertig-Outputs als weniger cachbar, als wenn man die Logik, die sich nicht ändert, dem Client übergibt.

            , dann die Seite gespeichert und tausende von Besuchern können sie abrufen, ohne auch nur ein Fitzelchen[^Fitzelchen] Energie ungewünschterweise in Wärmeenergie umzuwandeln.

            Ja, meine Bemerkung bezog sich noch auf einige andere Vorschläge.

            --
            Neu im Forum! Signaturen kann man ausblenden!
            1. Hello,

              [...]

              Sinnvoll fände ich deine clientseitige Lösung z. B. als Plugin für den Browser, das einem (clientseitig) ermöglicht, zusammengekotzt ausgelieferte Webseiten selbstständig zu analysieren/strukturieren.

              Ich habe das jetzt nicht recherchiert, aber vielleicht gibt es sowas sogar schon?

              Und wenn man das als Service anbieten will, bleiben auch wieder (mindestens) die zwei Wege: Seite auf dem Server analysieren oder JS-Modul zusammen mit einem Proxy-Clon der Seite ausliefern.

              Es muss jedenfalls erlaubt bleiben, darüber zu diskutieren :-P

              Liebe Grüße
              Tom S.

              --
              Es gibt nichts Gutes, außer man tut es!
              Das Leben selbst ist der Sinn.
              1. hallo

                Es muss jedenfalls erlaubt bleiben, darüber zu diskutieren :-P

                Ich dachte nicht, dass Rebell sein heute so billig ist.

                Mein Site-Design wird von einer main.js auf dem Client gesteuert. Das ganze wird auch dort gecacht. Die Lokale Navigation ist so nebenbei Bestandteil.

                KISS

                btw, meine Website funktioniert sogar aus dem Filesystem!

                --
                Neu im Forum! Signaturen kann man ausblenden!
                1. Ich dachte nicht, dass Rebell sein heute so billig ist.

                  Rebel

                  Mein Site-Design wird von einer main.js auf dem Client gesteuert. Das ganze wird auch dort gecacht. Die Lokale Navigation ist so nebenbei Bestandteil.

                  Sieht bei mir so aus:

                  Findet jetzt vielleicht nicht jeder toll, hat aber was.

                  1. Hallo Regina Schaukrug,

                    Findet jetzt vielleicht nicht jeder toll, hat aber was.

                    Fefe-like.

                    Bis demnächst
                    Matthias

                    --
                    Rosen sind rot.
                    1. hallo

                      Findet jetzt vielleicht nicht jeder toll, hat aber was.

                      Fefe-like.

                      Unsere Quelltexte kann man lesen. Dort endet dann aber auch alle Ähnlichkeit.

                      --
                      Neu im Forum! Signaturen kann man ausblenden!
                      1. Hallo

                        Findet jetzt vielleicht nicht jeder toll, hat aber was.

                        Fefe-like.

                        Unsere Quelltexte kann man lesen. Dort endet dann aber auch alle Ähnlichkeit.

                        Abgesehen von den thematischen Unterschieden, endet sie laut Screenshot nicht so schnell. Dass allerdings die Navigation ohne JavaScript überhaupt nicht vorhanden ist, ist tatsächlich ein gravierender Unterschied. Selbst wenn bei Fefe die Links zu den einzelnen Artikeln nur fitzelig klein sind, sie sind vorhanden. Bei dir sind sie es nicht.

                        Ja, du hast doch recht, die Ähnlichkeiten zwischen deiner und seiner Seite erschöpfen sich recht schnell.

                        Tschö, Auge

                        --
                        Eine Kerze stand [auf dem Abort] bereit, und der Almanach des vergangenen Jahres hing an einer Schnur. Die Herausgeber kannten ihre Leser und druckten den Almanach auf weiches, dünnes Papier.
                        Kleine freie Männer von Terry Pratchett
                        1. hallo

                          Dass allerdings die Navigation ohne JavaScript überhaupt nicht vorhanden ist, ist tatsächlich ein gravierender Unterschied. Selbst wenn bei Fefe die Links zu den einzelnen Artikeln nur fitzelig klein sind, sie sind vorhanden. Bei dir sind sie es nicht.

                          Das wird sich ändern, sobald wir <import> haben.

                          Alle Beschwerden über JS-Abhängigkeiten bitte ich solange an das w3c und die whatwg zu richten.

                          --
                          Neu im Forum! Signaturen kann man ausblenden!
                          1. Hallo

                            Dass allerdings die Navigation ohne JavaScript überhaupt nicht vorhanden ist, ist tatsächlich ein gravierender Unterschied. Selbst wenn bei Fefe die Links zu den einzelnen Artikeln nur fitzelig klein sind, sie sind vorhanden. Bei dir sind sie es nicht.

                            Das wird sich ändern, sobald wir <import> haben.

                            Alle Beschwerden über JS-Abhängigkeiten bitte ich solange an das w3c und die whatwg zu richten.

                            Wieso? Haben die deine Seite gebaut?

                            Tschö, Auge

                            --
                            Eine Kerze stand [auf dem Abort] bereit, und der Almanach des vergangenen Jahres hing an einer Schnur. Die Herausgeber kannten ihre Leser und druckten den Almanach auf weiches, dünnes Papier.
                            Kleine freie Männer von Terry Pratchett
          2. Hello,

            Dazu ist JS optimal.

            Das sehe ich anders.

            Ja klar. Energie kostet ja nichts!

            Das ist kein belegbares Argument. Siehe hierzu Matthias' Einspruch bezüglich eines möglichen Server-Caches.

            Die Programmausführung kostet Energie. Egal in welcher Sprache. Auf dem Server wird es ggf. einmal gemacht, dann die Seite gespeichert und tausende von Besuchern können sie abrufen, ohne auch nur ein Fitzelchen[^Fitzelchen] Energie ungewünschterweise in Wärmeenergie umzuwandeln.

            Das mag alles zu xx% richtig sein, aber die Idee, die Lösung ggf. auch auf der Clientseite zu suchen, muss erlaubt sein ;-)

            Allerdings stand die Frage schon im PHP-Kontext, was mich dann dazu veranlasst hat zuerst auf die beiden PHP-Klassen(-Sammlungen) zu verweisen. Wenn man es mit SimpleXML lösen kann, zerbröselt der Aufwand auf PHP-Seite nahezu zu 1%.

            Liebe Grüße
            Tom S.

            --
            Es gibt nichts Gutes, außer man tut es!
            Das Leben selbst ist der Sinn.
            1. Wenn man es mit SimpleXML lösen kann

              Naja... Mit SimpleXML könnte es schon beim Laden des "XML" Probleme geben:

              <p>: The end tag may be omitted if the <p> element is immediately followed by an <address>, <article>, <aside>, <blockquote>, <div>, <dl>, <fieldset>, <footer>, <form>, <h1>, <h2>, <h3>, <h4>, <h5>, <h6>, <header>, <hr>, <menu>, <nav>, <ol>, <pre>, <section>, <table>, <ul> or another <p> element, or if there is no more content in the parent element and the parent element is not an <a> element.

              <li>: The end tag can be omitted if the list item is immediately followed by another <li> element, or if there is no more content in its parent element.

              <td>: The end tag may be omitted, if it is immediately followed by a <th> or <td> element or if there are no more data in its parent element.

              <th>: The end tag may be omitted, if it is immediately followed by a <th> or <td> element or if there are no more data in its parent element.

              Testen wir das mal mit erlaubtem HTML… (Hinweis: Der Validator meckert nur den fehlenden <title> an.)

              <?php
              
              $html='<!DOCTYPE html>
              <html lang="de">
                <head>
                  <meta charset="utf-8">
                  <meta http-equiv="X-UA-Compatible" content="IE=Edge">
                  <meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no">
                </head>
                <body>
              	<h1>Hallo Welt!</h1>
              	<p>Lorem ipsum 
              	<p>Lorem ipsum 
              	<p>Lorem ipsum 
                </body>
              </html>';
              
              $xml = simplexml_load_string( $html );
              
              print_r( (array) $xml );
              

              Ups!

              PHP Warning:  simplexml_load_string(): Entity: line 7: parser error : Opening and ending tag mismatch: meta line 6 and head in /tmp/xml_simple_test.php on line 18
              PHP Stack trace:
              PHP   1. {main}() /tmp/xml_simple_test.php:0
              PHP   2. simplexml_load_string() /tmp/xml_simple_test.php:18
              PHP Warning:  simplexml_load_string():   </head> in /tmp/xml_simple_test.php on line 18
              PHP Stack trace:
              PHP   1. {main}() /tmp/xml_simple_test.php:0
              PHP   2. simplexml_load_string() /tmp/xml_simple_test.php:18
              PHP Warning:  simplexml_load_string():          ^ in /tmp/xml_simple_test.php on line 18
              PHP Stack trace:
              PHP   1. {main}() /tmp/xml_simple_test.php:0
              PHP   2. simplexml_load_string() /tmp/xml_simple_test.php:18
              PHP Warning:  simplexml_load_string(): Entity: line 13: parser error : Opening and ending tag mismatch: p line 12 and body in /tmp/xml_simple_test.php on line 18
              PHP Stack trace:
              PHP   1. {main}() /tmp/xml_simple_test.php:0
              PHP   2. simplexml_load_string() /tmp/xml_simple_test.php:18
              PHP Warning:  simplexml_load_string():   </body> in /tmp/xml_simple_test.php on line 18
              PHP Stack trace:
              PHP   1. {main}() /tmp/xml_simple_test.php:0
              PHP   2. simplexml_load_string() /tmp/xml_simple_test.php:18
              PHP Warning:  simplexml_load_string():          ^ in /tmp/xml_simple_test.php on line 18
              PHP Stack trace:
              PHP   1. {main}() /tmp/xml_simple_test.php:0
              PHP   2. simplexml_load_string() /tmp/xml_simple_test.php:18
              PHP Warning:  simplexml_load_string(): Entity: line 14: parser error : Opening and ending tag mismatch: p line 11 and html in /tmp/xml_simple_test.php on line 18
              PHP Stack trace:
              PHP   1. {main}() /tmp/xml_simple_test.php:0
              PHP   2. simplexml_load_string() /tmp/xml_simple_test.php:18
              PHP Warning:  simplexml_load_string(): Entity: line 14: parser error : Premature end of data in tag p line 10 in /tmp/xml_simple_test.php on line 18
              PHP Stack trace:
              PHP   1. {main}() /tmp/xml_simple_test.php:0
              PHP   2. simplexml_load_string() /tmp/xml_simple_test.php:18
              PHP Warning:  simplexml_load_string(): Entity: line 14: parser error : Premature end of data in tag body line 8 in /tmp/xml_simple_test.php on line 18
              PHP Stack trace:
              PHP   1. {main}() /tmp/xml_simple_test.php:0
              PHP   2. simplexml_load_string() /tmp/xml_simple_test.php:18
              PHP Warning:  simplexml_load_string(): Entity: line 14: parser error : Premature end of data in tag meta line 5 in /tmp/xml_simple_test.php on line 18
              PHP Stack trace:
              PHP   1. {main}() /tmp/xml_simple_test.php:0
              PHP   2. simplexml_load_string() /tmp/xml_simple_test.php:18
              PHP Warning:  simplexml_load_string(): Entity: line 14: parser error : Premature end of data in tag meta line 4 in /tmp/xml_simple_test.php on line 18
              PHP Stack trace:
              PHP   1. {main}() /tmp/xml_simple_test.php:0
              PHP   2. simplexml_load_string() /tmp/xml_simple_test.php:18
              PHP Warning:  simplexml_load_string(): Entity: line 14: parser error : Premature end of data in tag head line 3 in /tmp/xml_simple_test.php on line 18
              PHP Stack trace:
              PHP   1. {main}() /tmp/xml_simple_test.php:0
              PHP   2. simplexml_load_string() /tmp/xml_simple_test.php:18
              PHP Warning:  simplexml_load_string(): Entity: line 14: parser error : Premature end of data in tag html line 2 in /tmp/xml_simple_test.php on line 18
              PHP Stack trace:
              PHP   1. {main}() /tmp/xml_simple_test.php:0
              PHP   2. simplexml_load_string() /tmp/xml_simple_test.php:18
              Array
              (
                  [0] => 
              )
              
      2. @@Orlok

        Jedenfalls wenn das Skript im Browser ausgeführt werden soll, denn man kann sich nicht darauf verlassen, dass JS dort immer zur Verfügung steht. Vielleicht wurde JavaScript ausgeschaltet. Oder das jeweilige Skript konnte wegen schlechtem Empfang nicht vollständig geladen werden.

        Oder andere eingebundene Scripte die Ausführung des eigenen Scripts verhindern. Oder …

        In solchen Fällen gibt es dann kein Inhaltsverzeichnis, was die Benutzbarkeit der Seite stark einschränkt. Welcher Benutzer will schon bis herab zum Seitenende scrollen, nur um sich einen Überblick über den Inhalt zu verschaffen?

        Kommt drauf an. Wenn der Text eher darauf ausgelegt ist, linear in seiner Gänze gelesen zu werden, ist ein solches Inhaltsverzeichnis nice to have, kann also durchaus als progressive enhancement mit JavaScript implementiert werden.

        (Nutzer von Screenreadern sind hier klar im Vorteil, die können zur jeweils nächsten Überschrift springen.)

        Ein Inhaltsverzeichnis mit Links zu den jeweiligen Abschnitten einer Seite gehört für mich zu den Features, die auch dann verfügbar sein sollten, wenn JavaScript es nicht ist.

        Wie gesagt, das hängt vom Inhalt ab.

        LLAP 🖖

        --
        „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann