Python ElementTree генерирует неверно сформированный XML-файл со специальным символом '\x0b'
Я использовал ElementTree
для генерации xml со специальным символом '\x0b', затем используйте minidom
разобрать его. Это броситnot well-formed
ошибка.
import xml.etree.ElementTree as ET
from xml.dom import minidom
root = ET.Element('root')
root.text='\x0b'
xml = ET.tostring(root, 'UTF-8')
print(xml)
pretty_tree = minidom.parseString(xml)
Сгенерированный XML:<root>\x0b</root>
Ошибка:
Traceback (most recent call last):
File "testXml.py", line 7, in <module>
pretty_tree = minidom.parseString(xml)
File "/usr/local/Cellar/python/3.7.7/Frameworks/Python.framework/Versions/3.7/lib/python3.7/xml/dom/minidom.py", line 1968, in parseString
return expatbuilder.parseString(string)
File "/usr/local/Cellar/python/3.7.7/Frameworks/Python.framework/Versions/3.7/lib/python3.7/xml/dom/expatbuilder.py", line 925, in parseString
return builder.parseString(string)
File "/usr/local/Cellar/python/3.7.7/Frameworks/Python.framework/Versions/3.7/lib/python3.7/xml/dom/expatbuilder.py", line 223, in parseString
parser.Parse(string, True)
xml.parsers.expat.ExpatError: not well-formed (invalid token): line 1, column 6
3 ответа
Это поведение ранее рассматривалось как ошибка и решено как "не исправить".
Автор модуля ElementTree прокомментировал
Для ET [такое поведение] очень преднамеренно. Проверка данных, предоставляемых каждым отдельным приложением, снизит производительность для всех из них, даже если лишь незначительное меньшинство когда-либо попытается сериализовать данные, которые не могут быть представлены в XML.
Заключительный комментарий (от сопровождающего lxml, который также является разработчиком ядра Python) включает следующие наблюдения:
Это непростое решение. lxml, например, проверяет вводимые пользователем данные, но это потому, что он все равно должен его обрабатывать и делает это по пути непосредственно при вводе (и очень эффективно в коде C). ET, с другой стороны, довольно снисходительно относится к тому, что позволяет пользователям делать, и не применяет много обработки к вводу пользователя. Он даже допускает недопустимые деревья во время обработки и ожидает, что дерево будет сериализовано только при запросе на сериализацию.
Я думаю, что это справедливое поведение, потому что большая часть пользовательского ввода будет в порядке и не должна страдать от потери производительности из-за проверки всего ввода. Например, нулевые символы очень редко встречаются в тексте, и я думаю, что разумно позволить пользователям самостоятельно обрабатывать несколько случаев, когда они могут возникнуть.
...
В конце концов, пользователи, которые действительно заботятся о правильном выводе, должны запустить какую-то проверку схемы над ним после сериализации, так как это обнаружит не только проблемы с данными, но также структурные и логические проблемы (например, отсутствующий или пустой атрибут), особенно для их целевой формат данных. В некоторых случаях он может даже обнаружить случайное повреждение данных из-за старого ОЗУ без ECC на сервере.:)
...
Таким образом, ET.tostring
будет генерировать XML, который не имеет правильного формата, и это сделано намеренно. При необходимости вывод можно проанализировать, чтобы проверить его правильность, используяET.fromstring
или другой парсер. В качестве альтернативы можно использовать lxml вместо ElementTree.
\x0b
является ограниченным символом XML. В ответах на этот вопрос есть хорошее описание допустимых и запрещенных символов.
В качестве обходного пути для себя я написал вспомогательный метод для очистки ограниченных символов перед сохранением в модель XML:
def clean(str):
return re.sub(r'[^\u0009\u000A\u000D\u0020-\uD7FF\uE000-\uFFFD\u10000-\u10FFF]+', '', str)