Maneira interna de decodificar entidades HTML (ou seja, "ou")

11

Recentemente, tive o problema de decodificar entidades html. Eu tenho as seguintes duas seqüências de caracteres ( observe como dois métodos de codificação são usados, nomeados e numerados ).

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

E eu preciso convertê-los para

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

Pesquisando, encontrei essa pergunta antiga no SO (que é o que estou fazendo no momento), mas me recuso a acreditar que o Emacs não tem uma maneira integrada de fazer isso. Temos vários navegadores da web, pelo menos dois dos quais eu sei que estão embutidos, para não mencionar clientes de email e leitores de feeds.

Não existe uma maneira interna de decodificar entidades html?
Estou procurando uma função que pega uma string do primeiro exemplo e retorna uma string do segundo exemplo.

Malabarba
fonte
Se houver alguma coisa, aposto que deve estar no código nxml, pois é capaz de analisar DTDs e pode validar entidades no documento.
Wasamasa
libxml-parse-html-regionfaz isso, é claro, mas pode fazer mais do que você deseja, na medida em que analisa as tags HTML também ... (E nem todos os Emacs também são construídos com suporte a LibXML, eu acho).
9788 Jon O.

Respostas:

7

O Emacs inclui um analisador XML Elisp puro xml.el, cuja xml-parse-stringfunção faz o trabalho, embora pareça um pouco com uma função interna não documentada. Não tenho certeza se existem entidades apenas em HTML que não serão tratadas adequadamente tratando a string como um fragmento XML.

Essa função do wrapper simplesmente omitirá as tags à direita da string de entrada, embora você possa torná-la mais rígida:

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

No Emacs com suporte a LibXML, outra maneira um pouco hackista seria escrever um wrapper libxml-html-parse-region. Como o analisador LibXML assume que seu argumento é um documento HTML completo, a função wrapper precisa extrair os dados de caracteres analisados ​​da estrutura do documento retornado, usando pcase. Tentar decodificar uma string que contenha tags HTML produzirá um erro:

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

Resultados:

(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

Parece um pouco atrasado decodificar um fragmento de documento, analisando-o como um documento completo, apenas para retirar imediatamente as tags circundantes. Por outro lado, o uso do LibXML deve ser rápido e fornecer resultados precisos.

Jon O.
fonte
Desculpe, eu não tinha visto sua edição xml. Parece incrível.
Malabarba
Obrigado - editei a resposta para colocar a xml.elsolução mais simples em primeiro lugar.
Jon O.
@Malabarba Note que lisp/xml.elsempre incluiu a funçãoxml-substitute-special , que executa a mesma entidade decodificação como Jon O. dedecode-entities . No entanto, não omite as tags finais.
229 Basil Basil
2

web-mode.elfaz isso com web-mode-dom-entities-replace.

fxbois
fonte