Я пытаюсь удалить все в XML-документе между 2 тегами, с помощью Python и lxml., которым проблема состоит в том, что теги могут быть в различных ответвлениях дерева (но всегда на той же глубине), документ в качестве примера мог бы быть похожим на это.
<root>
<p> Hello world <start />this is a paragraph </p>
<p> Goodbye world. <end />I'm leaving now </p>
</root>
я хотел бы удалить все между запуском и конечными тэгами. который привел бы к единственному тегу p:
<root>
<p> Hello world I'm leaving now </p>
</root>
у кого-либо есть какая-либо идея, как это могло бы быть выполнено с помощью lxml и Python?
Вы можете попробовать использовать 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
, чтобы создать цель парсера
, и создайте собственный 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, требует пропуска всего между ....
и
по-прежнему будет приводить к правильно сформированному документу, как в вашем примере, но не было бы так, если бы второй
был
, например, так как вы получите
.
Я знаю, что есть люди, которые захотят побить меня камнями за это, но вы можете просто использовать регулярное выражение:
import re
new_string = re.sub(r'<start />(.*?)<end />', '', your_string, re.S)
Вы не можете использовать синтаксический анализатор XML, если это недопустимый XML.
У вас беспорядок в руках, и вам следует ударить человека, который написал преднамеренное искажение правила вложенности XML.
Вам, вероятно, лучше всего использовать что-то вроде SAX , чтобы распознать тег
и начать отбрасывать ввод, пока вы не нажмете
. SAX имеет здесь преимущество перед lxml, потому что он позволяет вам выполнять произвольные действия для каждой лексемы, в то время как lxml уже разделит начало и конец, прежде чем вы дойдете до них.
Пока вы занимаетесь этим, вы можете захотеть преобразовать эти документы в пригодный для использования XML.