特定の文字範囲が XML ドキュメントで許可されていないことはよく知られています。これらの文字を除外する解決策を認識しています ( [1]、[2]など)。
Don't Repeat Yourself の原則に従って、これらの解決策の 1 つを 1 つの中心点に実装したいと考えていますlxml
。これを達成する方法はありますか? たとえば、lxml
フィルター クラスをサブクラス化する、いくつかの例外をキャッチする、構成スイッチを設定するなどの方法がありますか?
編集:うまくいけば、この質問を少し明確にするために、ここにサンプルコードがあります:
from lxml import etree
root = etree.Element("root")
root.text = u'\uffff'
root.text += u'\ud800'
print(etree.tostring(root))
root.text += '\x02'.decode("utf-8")
これを実行すると結果が得られます
<root>�</root>
Traceback (most recent call last):
File "[…]", line 9, in <module>
root.text += u'\u0002'
File "lxml.etree.pyx", line 953, in lxml.etree._Element.text.__set__ (src/lxml/lxml.etree.c:44956)
File "apihelpers.pxi", line 677, in lxml.etree._setNodeText (src/lxml/lxml.etree.c:20273)
File "apihelpers.pxi", line 1395, in lxml.etree._utf8 (src/lxml/lxml.etree.c:26485)
ValueError: All strings must be XML compatible: Unicode or ASCII, no NULL bytes or control characters
ご覧のとおり、2 バイトに対して例外がスローされますが、lxml は範囲外の他の 2 文字を問題なくエスケープします。本当の問題は、
s = "<root>�</root>"
root = etree.fromstring(s)
も例外をスローします。この動作は、特に無効な XML ドキュメントを生成するため、私の意見では少し気がかりです。
これは 2 対 3 の問題である可能性があります。python3.4 では、上記のコードは例外をスローします。
Traceback (most recent call last):
File "[…]", line 5, in <module>
root.text += u'\ud800'
File "lxml.etree.pyx", line 953, in lxml.etree._Element.text.__set__ (src/lxml/lxml.etree.c:44971)
File "apihelpers.pxi", line 677, in lxml.etree._setNodeText (src/lxml/lxml.etree.c:20273)
File "apihelpers.pxi", line 1387, in lxml.etree._utf8 (src/lxml/lxml.etree.c:26380)
UnicodeEncodeError: 'utf-8' codec can't encode character '\ud800' in position 1: surrogates not allowed
残っている唯一の問題は、まだ喜んで受け入れる\uffff
キャラクターです。lxml