4 февр. 2009 г.

Нетекстовые символы в XML и HTML

Большнство разработчиков знают, что некоторые специальные символы в XML и HTML необходимо записывать в виде entity или character reference. Но мало кто подозревает, что XML (а также SGML, на котором базируется HTML) документы могут содержать только "текстовые" символы. Привычные питоновские библиотеки также обходят это требование стороной. Средства конструирования XML, которые, казалось бы, должны полностью защищать нас от создания "битых" документов, справляются со своей задачей лишь частично. В результате вполне возможна ситуация, когда библиотека ругается на созданный с её же помощью документ. Вот пример с использованием ElementTree:
>>> from xml.etree import ElementTree
>>> element = ElementTree.Element('element')
>>> element.text = u'\0'
>>> xml = ElementTree.tostring(element, encoding='utf-8')
>>> ElementTree.fromstring(xml)
[...]
xml.parsers.expat.ExpatError: not well-formed (invalid token): line 1, column 9
И то же самое с minidom:
>>> from xml.dom import minidom
>>> doc = minidom.getDOMImplementation().createDocument(None, None, None)
>>> element = doc.createElement('element')
>>> element.appendChild(doc.createTextNode(u'\0'))
<DOM Text node "">
>>> doc.appendChild(element)
<DOM Element: element at 0xb7ca688c>
>>> xml = doc.toxml(encoding='utf-8')
>>> minidom.parseString(xml)
[...]
xml.parsers.expat.ExpatError: not well-formed (invalid token): line 1, column 47
На мой взгляд, в описанной ситуации библиотека должна давать исключение ещё на стадии конструирования. Но даже если так и будет в будущих версиях, в реальной жизни это не решит проблему конкретного приложения, а лишь облегчит диагностику. Для web-приложений основной источник получения потенциально плохих данных — через форму. И было бы правильно проверять или очищать данные на стадии получения их от пользователя. Однако и здесь всё плохо: из всех известных мне библиотек для обработки и валидации форм только одна (весьма древняя и малоизвестная) решает проблему нетекстовых символов, хотя большинство вполне корректно работают с "битыми" кодировками.