9

特定の文字範囲が 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>&#65535;&#55296;</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>&#65535;&#55296;</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

4

1 に答える 1

1

LXML で解析する前に文字列をフィルタリングするだけです: XML から無効な文字を消去します (gist by lawlesst)

あなたのコードで試してみました。動作するようですが、 gist を変更してreおよびsysをインポートする必要があるという事実を保存してください。

from lxml import etree
from cleaner import invalid_xml_remove

root = etree.Element("root")
root.text = u'\uffff'
root.text += u'\ud800' 

print(etree.tostring(root))

root.text += invalid_xml_remove('\x02'.decode("utf-8"))
于 2015-01-22T17:00:26.660 に答える