Auto Links auf definierte Suchwörter

  • Hallo Forum! :)


    Sicherlich ist es eine triviale Funktion und ich sehe nur mangels tiefergehender Kenntnis den Wald vor lauter Bäumen nicht.

    Ich möchte gerne für alle Nachrichten eine Auto-Link-Funktion einbauen. Im Hintergrund habe ich eine Tabelle in der Suchwort/Ersatzurl/Titel stehen. Diese möchte ich auf alle Nachrichten anwenden, dass die Suchwörter aus der Tabelle in den Nachrichten automatisch gefunden und verlinkt werden - auch (und vor allem) für den bereits bestehenden Content. Ohne Worker und nicht nur "ab sofort bei neuen Einträgen", sondern dann halt on the fly.

    Ich bin nun soweit dass ich ein kleines Plugin mit einem EventListener auf HtmlOutputNodeProcessor (beforeProcess) geschrieben habe.

    Mit $eventObj->getDocument()->getElementsByTagName('p'); hole ich mir die Paragraphen und laufe die in einer Scheife durch.

    Prinzipiell kann ich auch die Suchwörter finden in $node->textContent, gegen HTML Code ersetzen kann ich aber nicht. Der Link-HTML-Code wird dann einfach als Text ausgegeben, was zugegebenermaßen auch nicht ganz unverständlich ist. ;)

    Also habe ich angefangen wie wild mittels $node->ownerDocument->createElement(); neue Elemente zu erstellen um am Ende die matches vor dem Suchwort, dann das verlinkte Suchwort selbst und dann den match nach dem Suchwort so zusammenzubauen, dass es irgendwie passt. Das ist aber mehr als unelegant und so richtig zum Ziel komme ich damit auch nicht.


    Kurz das Wesentliche, auch wenn es eben nicht zielführend ist. Das Ganze nur zu Testzwecken ohne RegExp sondern mit einfachem str_replace.

    Code
    1. public function execute($eventObj, $className, $eventName, array &$parameters) {
    2. $nodes = $eventObj->getDocument()->getElementsByTagName('p');
    3. foreach($nodes AS $node){
    4. foreach($this->data AS $key => $val){
    5. if(stristr($node->textContent,$key)){
    6. $node->textContent = str_replace($key, '<a href="$val">'.$key.'</a>', $node->textContent);
    7. }
    8. }
    9. }
    10. }

    Nochmal: Ich möchte in allen Nachrichten extern definierte und eingelesene Suchwörter ($this->data) mit einem Link versehen. Wo setze ich da am besten an? Die Möglichkeit dass über die BB-Codes und beim Absenden direkt in den Datensatz zu schreiben, möchte ich vermeiden, da die Liste sich häufiger mal ändert und zum anderen das Forum seit 2001 existiert - der meiste Content also bereits geschrieben ist, die Suchwörter überschaubar, aber in recht häufiger Anpassung.


    Ich glaube bei HtmlOutputNodeProcessor bin ich in eine Sackgasse gefahren bzw. setze zu spät an?!

    Kann mir hier jemand einen Tipp geben an welcher Stelle ich falsch abgebogen bin und wo ich eigentlich hin muss? :/


    Schöne Ostern!

    Armin

  • Hallo,


    die PHP-DOM-Implementierung funktioniert genau wie die DOM-API im Browser, u. a. ist textContent genau das, was der Name impliziert: Text. Es ist nicht möglich, mit textContent irgendwelche HTML-Elemente zu erzeugen, aber es gibt andere Wege! :) Der Ansatz ist grundsätzlich korret, einzig die Änderung des textContent ist eine Sackgasse.


    Ich habe den äußeren Code mal weggelassen, mein Code beschäftigt sich nur mit dem Teil in deinem inneren foreach:

    Der Code macht im Prinzip das folgende:

    1. Sucht die Position von $key, falls es vorkommt.
    2. Erzeugt eine neue Text-Node mit dem gesamten Text bis vor $key und fügt ihn vor dem anderen Text ein.
    3. Der Link wird erzeugt und nach dem in Schritt 2 eingefügten Text eingefügt, aber noch vor dem Original-Text - letzterer ist immer noch unverändert!
    4. Im letzten Schritt wird der Original-Text so beschnitten, dass nur noch der Teil nach $key stehen bleibt.

    Als Beispiel in Farbe, gesucht ist das Wort Welt:

    1. <p>Hallo Welt!</p>
    2. <p>Hallo Hallo Welt!</p>
    3. <p>Hallo <a href="#">Welt</a>Hallo Welt!</p>
    4. <p>Hallo <a href="#">Welt</a>!</p>
  • Müsste er dafür aber nicht explizit die textnodes parsen, denn wenn er sonst irgend welche Formatierungen enthält gingen die doch verloren ?

    Code
    1. foreach ($eventObj->getXPath()->query('//text()') as $node) {
    2. // yadda yadda yadda
    3. }

    Sowas in der Art sollte mMn eher funzen...

  • Ja, natürlich, daran hatte ich so spät nicht mehr gedacht :)


    Es wird auch noch dadurch erschwert, das die selbe Text-Node mehrere Matches enthalten kann. Im Prinzip müsste es vom Ablauf her wie der HtmlInputNodeTextParser arbeiten …

  • Vielen Dank euch Beiden für eure Hilfe!

    Dann war ich mit, wie ich schrieb, "wildem createElement()", ja doch auf der richtigen Spur. :)

    Mir schien das nur etwas zu "viel des Guten" für einen im Grunde einfachen regulären Ausdruck auf einen String.


    Die Möglichkeit den aus der Datenbank geholten, jungfräulichen Inhalt, direkt zu manipulieren habe ich nicht?


    Sonnige Grüße

    Armin

  • Hi,


    ohne deine Requirements genau zu kennen, würde nicht das Lexikon genau deine Anforderungen erfüllen? Das kann Begriffe in Texten automatisch erkennen und verlinkt das mit einem Artikel im Lexikon. Die Erkennung erfolgt live und ist für alle Beiträge sofort verfügbar (auch nachträglich)


  • Die Möglichkeit den aus der Datenbank geholten, jungfräulichen Inhalt, direkt zu manipulieren habe ich nicht?

    Es gibt durchaus die Möglichkeit dazu, allerdings ist das system nicht ohne Grund so regide und zwingt dich dazu es "richtig" zu machen.

    Konkret könntest du durchgehen und den gesammten HTML Inhalt via $html = $eventObj->getDocument()->saveHTML($eventObj->->getDocument()->getElementsByTagName('body')->item(0)); auslesen und danach via $eventObj->load($eventObj->getHtmlProcessor(), $html); neu laden, aber damit machst du dich eher unbeliebt^^

  • Hi,


    ohne deine Requirements genau zu kennen, würde nicht das Lexikon genau deine Anforderungen erfüllen? Das kann Begriffe in Texten automatisch erkennen und verlinkt das mit einem Artikel im Lexikon. Die Erkennung erfolgt live und ist für alle Beiträge sofort verfügbar (auch nachträglich)

    Das Lexikon setzen wir seit 2015 bereits ein und haben da über 650 Begriffen hinterlegt. :)

    https://www.drachenforum.net/lexikon/index.php/Lexicon/


    Es geht mir aber konkret um variierende Begriffe (so 20-30 im Mittel) eines bestehenden Systems, welches ich zumindest rudimentär in den eigentlichen Inhalten verknüpfen will. Auf der Seite läuft ja noch das alte 4.1. Ich wollte dieses Jahr dann auch dort endlich mal updaten und längst notwendige "Vereinigungen" durchführen. Wir haben da noch einige Subdomains mit externem Content die ich unter die Haube des Hauptsystems bringen will. Unsere DraDaBa (Drachen Datenbank) möchte irgendwann auch mal eine eigene Anwendung im System werden. ( http://dradaba.drachenforum.net/ ) Da stehe ich dann wieder vor selbigem Problem wie jetzt, da ich natürlich die einzelnen Produkte, wenn sie im restlichen Inhalt genannt werden, direkt verlinken möchte.


    Morik Das scheint mir auch eher wie mit Kanonen auf Spatzen zu schießen, aber danke! :) Mein Gedanke war dass ich den als String aus der Datenbank gezogenen Inhalt vielleicht an irgendeiner Stelle bearbeiten kann, bevor er auf die Reise durchs System geschickt wird.

  • Morik Das scheint mir auch eher wie mit Kanonen auf Spatzen zu schießen, aber danke! :) Mein Gedanke war dass ich den als String aus der Datenbank gezogenen Inhalt vielleicht an irgendeiner Stelle bearbeiten kann, bevor er auf die Reise durchs System geschickt wird.

    Nicht zentral gesteuert, an einzelnen stellen ginge das eventuell, aber aus Konsistenz gründen würde ich es nicht empfehlen.