Manière intégrée de décoder les entités HTML (c.-à-d. & Quot; ou & # 39;)


11

J'ai récemment rencontré le problème du décodage des entités html. J'ai les deux chaînes suivantes ( notez comment deux méthodes d'encodage sont utilisées, nommées et numérotées ).

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

Et je dois les convertir en

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

En cherchant, j'ai trouvé cette vieille question sur SO (ce que je fais pour le moment), mais je refuse de croire qu'Emacs n'a pas de méthode intégrée pour le faire. Nous avons plusieurs navigateurs Web, dont au moins deux dont je sais qu'ils sont intégrés, sans parler des clients de messagerie et des lecteurs de flux.

N'y a-t-il pas un moyen intégré de décoder les entités html?
Je recherche une fonction qui prend une chaîne du premier exemple et renvoie une chaîne du deuxième exemple.


S'il y a quelque chose, je parie qu'il doit être dans le code nxml car il est capable d'analyser les DTD et de valider les entités dans le document.
wasamasa

libxml-parse-html-regionfait cela, bien sûr, mais il peut faire plus que ce que vous voulez, car il analyse également les balises HTML… (Et tous les Emacs ne sont pas non plus construits avec le support LibXML, je suppose).
Jon O.

Réponses:


7

Emacs comprend un analyseur XML Elisp pur xml.el, dont la xml-parse-stringfonction fait le travail, bien qu'il ressemble un peu à une fonction interne non documentée. Je ne sais pas s'il existe des entités HTML uniquement qui ne seront pas correctement gérées en traitant la chaîne comme un fragment XML.

Cette fonction wrapper omettra simplement toutes les balises de fin de la chaîne d'entrée, bien que vous puissiez la rendre plus stricte:

(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: "

Dans Emacs avec la prise en charge de LibXML, une autre façon légèrement hackée serait d'écrire un wrapper libxml-html-parse-region. Étant donné que l'analyseur LibXML suppose que son argument est un document HTML complet, la fonction wrapper doit extraire les données de caractères analysées de la structure de document retournée, à l'aide de pcase. Essayer de décoder une chaîne contenant des balises HTML produira une erreur:

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

Résultats:

(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

Il semble un peu en arrière de décoder un fragment de document en l'analysant comme un document complet, pour ensuite retirer immédiatement les balises environnantes. En revanche, l'utilisation de LibXML doit être rapide et donner des résultats précis.


Désolé, je n'avais pas vu votre modification XML. Ça a l'air génial.
Malabarba

Merci - j'ai modifié la réponse pour mettre la xml.elsolution la plus simple en premier.
Jon O.

@Malabarba Notez qu'il lisp/xml.ela toujours inclus la fonction xml-substitute-special, qui effectue le même décodage d'entité que Jon Odecode-entities .. Il n'omet cependant pas les balises de fin.
Basil

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.