Cara bawaan untuk mendekode entitas HTML (yaitu & quot; atau & # 39;)

11

Saya baru-baru ini mengalami masalah decoding entitas html. Saya memiliki dua string berikut ( Perhatikan bagaimana dua metode pengkodean digunakan, dinamai dan diberi nomor ).

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

Dan saya perlu mengubahnya menjadi

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

Mencari-cari di sekitar, saya menemukan pertanyaan lama ini pada SO (yang adalah apa yang saya lakukan untuk saat ini), tetapi saya menolak untuk percaya Emacs tidak memiliki cara bawaan untuk melakukan ini. Kami memiliki beberapa browser web, setidaknya dua di antaranya saya tahu adalah built-in, belum lagi klien email dan pembaca feed.

Apakah tidak ada cara bawaan untuk mendekode entitas html?
Saya mencari fungsi yang mengambil string dari contoh pertama dan mengembalikan string dari contoh kedua.

Malabarba
sumber
Jika ada sesuatu, saya yakin itu harus dalam kode nxml karena dapat mem-parsing DTD dan dapat memvalidasi entitas dalam dokumen.
wasamasa
libxml-parse-html-regionmelakukan ini, tentu saja, tetapi mungkin melakukan lebih dari yang Anda inginkan, dalam hal itu mem-parsing tag HTML juga ... (Dan tidak semua Emacs dibangun dengan dukungan LibXML, kurasa).
Jon O.

Jawaban:

7

Emacs menyertakan parser XML murni-Elisp xml.el, yang xml-parse-stringfungsinya melakukan pekerjaan, meskipun sepertinya sedikit seperti fungsi internal tidak berdokumen. Saya tidak yakin apakah ada entitas hanya HTML yang tidak akan ditangani dengan benar dengan memperlakukan string sebagai fragmen XML.

Fungsi wrapper ini hanya akan menghilangkan tag tambahan dari string input, meskipun Anda bisa membuatnya lebih ketat:

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

Dalam Emacs dengan dukungan LibXML, cara lain yang sedikit meretas adalah dengan menulis pembungkus libxml-html-parse-region. Karena parser LibXML menganggap argumennya adalah dokumen HTML yang lengkap, fungsi wrapper harus mengekstrak data karakter parsing dari struktur dokumen yang dikembalikan, menggunakan pcase. Mencoba memecahkan kode string yang berisi tag HTML apa pun akan menghasilkan kesalahan:

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

Hasil:

(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

Tampaknya sedikit terbelakang untuk memecahkan kode fragmen dokumen dengan menguraikannya sebagai dokumen yang lengkap, hanya untuk segera menghapus tag sekitarnya. Di sisi lain, menggunakan LibXML harus cepat dan memberikan hasil yang akurat.

Jon O.
sumber
Maaf, saya belum melihat hasil edit xml Anda. Terlihat mengagumkan.
Malabarba
Terima kasih - Saya mengedit jawaban untuk menempatkan xml.elsolusi yang lebih sederhana terlebih dahulu.
Jon O.
@Malabarba Perhatikan bahwa lisp/xml.elselalu disertakan fungsi xml-substitute-special, yang melakukan entitas yang sama decoding seperti Jon O. inidecode-entities . Namun, itu tidak menghilangkan tag tambahan.
Basil
2

web-mode.elmelakukan ini dengan web-mode-dom-entities-replace.

fxbois
sumber