Синтаксический разбор нецелых XML
XML спецификация предписывает, что все XML синтаксические анализаторы должны выполнять «драконову (строгую) обработку ошибок». То есть, при обнаружении в XML документе формальной ошибки или не«правильнопостроенности» (wellformedness) анализаторы должны сразу же прервать анализ и «вспыхнуть». Ошибки правильнопостроенности включают несогласованность открывающих и закрывающих тэгов, неопределённые элементы, неправильные символы Юникод и другие эзотерические ситуации. Такая обработка ошибок сильно контрастирует на фоне других известных форматов, например, HTML — браузер не останавливается отрисовывать web-страницу если в странице забыт закрывающий HTML тэг или значение атрибута тэга содержит неэкранированный амперсанд. (Существует распространённое заблуждение, что в формате HTML не оговорена обработка ошибок. На самом деле, обработка HTML ошибок отлично документирована, но она гораздо сложнее чем просто «остановиться и загореться на первой ошибке». ) Некоторые считают (и я в том числе), что это было ошибкой со стороны разработчиков формата XML заставлять так строго обрабатывать ошибки. Не поймите меня неправильно, я конечно же за упрощение правил обработки ошибок. Однако, на практике понятие «правильнопостроенности» оказывается коварнее чем кажется, особенно для XML документов которые публикуются в интернете и передаются по протоколу HTTP (например, фиды Atom). Несмотря на зрелость XML, который стандартизовал драконову обработку ошибок в 1997, исследования постоянно показывают, что значительная часть фидов Atom в интернете содержат ошибки правильнопостроенности. Итак, у меня есть и теоретические и практические причины обрабатывать XML документы «любой ценой», то есть не останавливаться и взрываться при первой ошибке. Если Вы окажетесь в похожей ситуации, то lxml может помочь.
Ниже приведён фрагмент «битого» XML документа. <? xml version='1. 0' encoding='utf-8'? > < feed xmlns='http: //www. w3. org/2005/Atom' xml: lang='en'> < title> dive into & hellip; < /title>... < /feed>В фиде ошибка, так как последовательность & hellip; не определена в формате XML (она определена в HTML). Если попробовать разобрать битый фид с настройками по умолчанию, то lxml споткнётся на неопределённом вхождении hellip. > > > import lxml. etree> > > tree = lxml. etree. parse('examples/feed-broken. xml')Traceback (most recent call last): File " < stdin> ", line 1, in < module> File " lxml. etree. pyx", line 2693, in lxml. etree. parse (src/lxml/lxml. etree. c: 52591) File " parser. pxi", line 1478, in lxml. etree. _parseDocument (src/lxml/lxml. etree. c: 75665) File " parser. pxi", line 1507, in lxml. etree. _parseDocumentFromURL (src/lxml/lxml. etree. c: 75993) File " parser. pxi", line 1407, in lxml. etree. _parseDocFromFile (src/lxml/lxml. etree. c: 75002) File " parser. pxi", line 965, in lxml. etree. _BaseParser. _parseDocFromFile (src/lxml/lxml. etree. c: 72023) File " parser. pxi", line 539, in lxml. etree. _ParserContext. _handleParseResultDoc (src/lxml/lxml. etree. c: 67830) File " parser. pxi", line 625, in lxml. etree. _handleParseResult (src/lxml/lxml. etree. c: 68877) File " parser. pxi", line 565, in lxml. etree. _raiseParseError (src/lxml/lxml. etree. c: 68125)lxml. etree. XMLSyntaxError: Entity 'hellip' not defined, line 3, column 28Для того чтобы обрабатывать XML документ с ошибками, необходимо создать новый синтаксический анализатор XML. > > parser = lxml. etree. XMLParser(recover=True) ① > > > tree = lxml. etree. parse('examples/feed-broken. xml', parser) ② > > > parser. error_log ③ examples/feed-broken. xml: 3: 28: FATAL: PARSER: ERR_UNDECLARED_ENTITY: Entity 'hellip' not defined> > > tree. findall('{http: //www. w3. org/2005/Atom}title')[< Element {http: //www. w3. org/2005/Atom}title at ead510> ]> > > title = tree. findall('{http: //www. w3. org/2005/Atom}title')[0]> > > title. text ④ 'dive into '> > > print(lxml. etree. tounicode(tree. getroot())) ⑤ < feed xmlns='http: //www. w3. org/2005/Atom' xml: lang='en'> < title> dive into < /title>.. [остальной вывод сериализации пропущен для краткости].① Для того чтобы создать новый анализатор мы создаём новый класс lxml. etree. XMLParser. Хотя он может принимать много разных параметров, для нас представляет интерес только один — аргумент восстановления recover. При присвоении аргументу значения True lxml будет из кожи вон лезть чтобы восстановить ошибки правильнопостроенности.
② Для того чтобы разобрать XML документ новым анализатором мы передаём объект parser в качестве второго аргумента в функцию parse(). На этот раз lxml не выбрасывает исключительную ситуацию при неопределённой последовательности & hellip;. ③ Анализатор содержит сообщения обо всех найденных ошибках. (На самом деле эти сообщения сохраняются независимо от параметра recover. ) ④ Так как анализатор не знает что делать с неопределённым & hellip;, то он просто выбрасывает слово. Текстовое содержание элемента title превращается в 'dive into '. ⑤ И ещё раз: после сериализации последовательность & hellip; исчезла, lxml её выбросил. Важно отметить, что нет никакой гарантии переносимости восстановления ошибок у XML анализаторов. Другой анализатор может быть умнее и распознать что & hellip; является валидной последовательностью HTML и восстановить её как амперсанд. «Лучше» ли это? Возможно. Является ли это «более правильным»? Нет, так как оба решения с точки зрения формата XML неверны. Правильное поведение (согласно XML спецификации) прекратить обработку и загореться. Если же необходимо не следовать спецификации, то Вы делаете это на свой страх и риск.
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|