Emacsにはに純粋なElisp XMLパーサーが含まれていますxml.el
。そのxml-parse-string
機能はその役割を果たしますが、ドキュメント化されていない内部関数のように見えます。文字列をXMLフラグメントとして処理することで適切に処理されないHTMLのみのエンティティがあるかどうかはわかりません。
このラッパー関数は、入力文字列から末尾のタグを単に省略しますが、より厳密にすることもできます。
(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: "
LibXMLをサポートするEmacsでは、もう1つのちょっとハックな方法は、ラッパーを記述することlibxml-html-parse-region
です。LibXMLパーサーは、引数が完全なHTMLドキュメントであると想定しているため、ラッパー関数は、を使用して、返されたドキュメント構造から解析された文字データを抽出する必要がありpcase
ます。HTMLタグを含む文字列をデコードしようとすると、エラーが発生します。
(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))))))
結果:
(decode-entities/libxml "The old "how to fold xml" question")
; => "The old \"how to fold xml\" question"
(decode-entities/libxml "doesn't") ; => "doesn't"
(decode-entities/libxml "<html>") ; produces an error
完全なドキュメントとして解析することによってドキュメントフラグメントをデコードすることは少し後方に見えますが、周囲のタグをすぐに取り除くだけです。一方、LibXMLを使用すると、高速で正確な結果が得られます。