Я тоже столкнулся с этим, получив данные \x16
(символ Unicode 'синхронный режим ожидания' или 'SYN', отображаемый в xml как ^V
), что приводит к ошибке при разборе xml: XMLSyntaxError: PCDATA invalid Char value 22.
22 потому что ord('\x16')
равно 22.
Ответ @michael поставил меня на правильный путь. Но некоторые управляющие символы ниже 32 в порядке, такие как возврат или табуляция, а несколько старших символов все еще плохие. Итак:
# Get list of bad characters that would lead to XMLSyntaxError.
# Calculated manually like this:
from lxml import etree
from StringIO import StringIO
BAD = []
for i in range(0, 10000):
try:
x = etree.parse(StringIO('<p>%s</p>' % unichr(i)))
except etree.XMLSyntaxError:
BAD.append(i)
Это приводит к списку из 31 символа, который может быть жестко закодирован вместо выполнения вышеуказанного вычисления в коде:
BAD = [
0, 1, 2, 3, 4, 5, 6, 7, 8,
11, 12,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
# Two are perfectly valid characters but go wrong for different reasons.
# 38 is '&' which gives: xmlParseEntityRef: no name.
# 60 is '<' which gives: StartTag: invalid element namea different error.
]
BAD_BASESTRING_CHARS = [chr(b) for b in BAD]
BAD_UNICODE_CHARS = [unichr(b) for b in BAD]
Тогда используйте это так:
def remove_bad_chars(value):
# Remove bad control characters.
if isinstance(value, unicode):
for char in BAD_UNICODE_CHARS:
value = value.replace(char, u'')
elif isinstance(value, basestring):
for char in BAD_BASESTRING_CHARS:
value = value.replace(char, '')
return value
Если value
равен 2 гигабайту, вам, возможно, потребуется сделать это более эффективным способом, но я игнорирую это здесь, хотя вопрос упоминает об этом. В моем случае я создаю xml-файл, но мне нужно разобраться с этими символами в исходных данных, поэтому я буду использовать эту функцию перед помещением данных в xml.