Вы можете попробовать использовать SAX-подобный целевой интерфейс синтаксического анализатора :
from lxml import etree
class SkipStartEndTarget:
def __init__(self, *args, **kwargs):
self.builder = etree.TreeBuilder()
self.skip = False
def start(self, tag, attrib, nsmap=None):
if tag == 'start':
self.skip = True
if not self.skip:
self.builder.start(tag, attrib, nsmap)
def data(self, data):
if not self.skip:
self.builder.data(data)
def comment(self, comment):
if not self.skip:
self.builder.comment(self)
def pi(self, target, data):
if not self.skip:
self.builder.pi(target, data)
def end(self, tag):
if not self.skip:
self.builder.end(tag)
if tag == 'end':
self.skip = False
def close(self):
self.skip = False
return self.builder.close()
Затем можно использовать класс SkipStartEndTarget
, чтобы создать parser target
и создать пользовательскийXMLParser
с этой целью, например:
parser = etree.XMLParser(target=SkipStartEndTarget())
Вы можете предоставить другие параметры синтаксического анализатора, если они вам нужны.Затем вы можете предоставить этот синтаксический анализатор для используемой вами функции синтаксического анализатора, например:
elem = etree.fromstring(xml_str, parser=parser)
Это также работает с etree.XML()
и etree.parse()
, и вы даже можете установить синтаксический анализатор как синтаксический анализатор по умолчанию сetree.setdefaultparser()
(что, вероятно, не очень хорошая идея).Одна вещь, которая может сбить вас с толку: даже с etree.parse()
это не вернет дерево элементов, но всегда элемент (как это делают etree.XML()
и etree.fromstring()
).Я не думаю, что это может быть сделано (пока), поэтому, если это проблема для вас, вам придется как-то обойти это.
Обратите внимание, что также можно использовать создание элемента дерева из saxсобытия с lxml.sax , что, вероятно, несколько сложнее и медленнее.Вопреки приведенному выше примеру, он вернет элементное дерево, но я думаю, что он не обеспечивает .docinfo
, которое вы получите при обычном использовании etree.parse()
.Я также считаю, что он (в настоящее время) не поддерживает комментарии и пи.(еще не использовал, поэтому я не могу быть более точным в данный момент)
Также обратите внимание, что любой SAX-подобный подход к анализу документа требует пропуска всего между <start/>
и <end/>
по-прежнему будет иметь правильно сформированный документ, что имеет место в вашем примере, но не будет, если второй <p>
был, например, <p2>
, так как в итоге вы получили бы <p>....</p2>
.