Integrierte Methode zum Dekodieren von HTML-Entitäten (z. B. "oder")

11

Ich bin kürzlich auf das Problem gestoßen, HTML-Entitäten zu dekodieren. Ich habe die folgenden zwei Zeichenfolgen ( Beachten Sie, wie zwei Codierungsmethoden verwendet werden, benannt und nummeriert ).

The old "how to fold xml" question
Babel doesn't wrap results in verbatim

Und ich muss sie konvertieren

The old "how to fold xml" question
Babel doesn't wrap results in verbatim

Als ich mich umsah, fand ich diese alte Frage auf SO (was ich gerade mache), aber ich weigere mich zu glauben, dass Emacs keine eingebaute Möglichkeit hat, dies zu tun. Wir haben mehrere Webbrowser, von denen ich weiß, dass mindestens zwei integriert sind, ganz zu schweigen von Mail-Clients und Feed-Readern.

Gibt es keine integrierte Methode zum Dekodieren von HTML-Entitäten?
Ich suche nach einer Funktion, die eine Zeichenfolge aus dem ersten Beispiel nimmt und eine Zeichenfolge aus dem zweiten Beispiel zurückgibt.

Malabarba
quelle
Wenn es irgendetwas gibt, muss es im nxml-Code sein, da es DTDs analysieren und Entitäten im Dokument validieren kann.
Wasamasa
libxml-parse-html-regiontut dies natürlich, aber es kann mehr als Sie wollen, da es auch HTML-Tags analysiert… (und ich denke, nicht alle Emacs werden mit LibXML-Unterstützung erstellt).
Jon O.

Antworten:

7

Emacs enthält einen reinen Elisp-XML-Parser xml.el, dessen xml-parse-stringFunktion die Aufgabe übernimmt, obwohl es ein bisschen wie eine undokumentierte interne Funktion erscheint. Ich bin nicht sicher, ob es nur HTML-Entitäten gibt, die nicht richtig behandelt werden, wenn die Zeichenfolge als XML-Fragment behandelt wird.

Diese Wrapper-Funktion lässt einfach alle nachfolgenden Tags in der Eingabezeichenfolge weg, obwohl Sie sie strenger gestalten könnten:

(defun decode-entities (html)
  (with-temp-buffer
    (save-excursion (insert html))
    (xml-parse-string)))

(decode-entities "The old "how to fold xml" question")
;; => "The old \"how to fold xml\" question"

(decode-entities "doesn't")
;; => "doesn't"

(decode-entities "string with trailing tag: <tag/>")
;; => "string with trailing tag: "

In Emacs mit LibXML-Unterstützung besteht eine andere, etwas hackige Möglichkeit darin, einen Wrapper herumzuschreiben libxml-html-parse-region . Da der LibXML-Parser davon ausgeht, dass sein Argument ein vollständiges HTML-Dokument ist, muss die Wrapper-Funktion die analysierten Zeichendaten mithilfe von aus der zurückgegebenen Dokumentstruktur extrahieren pcase. Der Versuch, eine Zeichenfolge zu dekodieren, die HTML-Tags enthält, führt zu einem Fehler:

(defun decode-entities/libxml (html)
  (with-temp-buffer
    (insert html)
    (let ((document
           (libxml-parse-html-region (point-min) (point-max))))
      (pcase document
        (`(html nil
                (body nil
                      (p nil
                         ,(and (pred stringp)
                               content))))
          content)
        (_ (error "Unexpected parse result: %S" document))))))

Ergebnisse:

(decode-entities/libxml "The old &quot;how to fold xml&quot; question")
     ; => "The old \"how to fold xml\" question"
(decode-entities/libxml "doesn&#39;t") ; => "doesn't"

(decode-entities/libxml "<html>")              ; produces an error

Es scheint ein wenig rückständig zu sein, ein Dokumentfragment zu dekodieren, indem es als vollständiges Dokument analysiert wird, um dann die umgebenden Tags sofort zu entfernen. Andererseits sollte die Verwendung von LibXML schnell sein und genaue Ergebnisse liefern.

Jon O.
quelle
Entschuldigung, ich habe Ihre XML-Bearbeitung nicht gesehen. Schaut toll aus.
Malabarba
Danke - Ich habe die Antwort bearbeitet, um die einfachere xml.elLösung an die erste Stelle zu setzen.
Jon O.
@Malabarba Beachten Sie, dass lisp/xml.elimmer die Funktion enthalten war xml-substitute-special, die dieselbe Entitätsdecodierung wie die von Jon O.decode-entities ausführt . Nachfolgende Tags werden jedoch nicht ausgelassen.
Basil
2

web-mode.elmacht das mit web-mode-dom-entities-replace.

fxbois
quelle