Nano Hash - криптовалюты, майнинг, программирование

Использование Python xml.etree для поиска смещений начального и конечного символов элемента

У меня есть данные XML, которые выглядят так:

<xml>
The captial of <place pid="1">South Africa</place> is <place>Pretoria</place>.
</xml>

Я хотел бы иметь возможность извлечь:

  1. XML-элементы в том виде, в каком они в настоящее время представлены в etree.
  2. Полный текст документа между начальным и конечным тегами.
  3. Расположение в простом тексте каждого начального элемента в виде смещения символа.

(3) сейчас самое важное требование; etree обеспечивает (1) штраф.

Я не вижу никакого способа сделать (3) напрямую, но надеялся, что повторение элементов в дереве документа вернет много небольших строк, которые можно было бы повторно собрать, таким образом предоставив (2) и (3). Однако запрос .text корневого узла возвращает только текст между корневым узлом и первым элементом, например. "Столица ".

Выполнение (1) с SAX может включать в себя реализацию многого, что уже было написано много раз, например. минидом и этри. Использование lxml не подходит для пакета, в который должен войти этот код. Кто-нибудь может помочь?

13.11.2011

Ответы:


1

Функция iterparse() доступна в xml.etree:

import xml.etree.cElementTree as etree

for event, elem in etree.iterparse(file, events=('start', 'end')):
    if event == 'start':
       print(elem.tag) # use only tag name and attributes here
    elif event == 'end':
       # elem children elements, elem.text, elem.tail are available
       if elem.text is not None and elem.tail is not None:
          print(repr(elem.tail))

Другой вариант — переопределить методы start(), data(), end() для etree.TreeBuilder():

from xml.etree.ElementTree import XMLParser, TreeBuilder

class MyTreeBuilder(TreeBuilder):

    def start(self, tag, attrs):
        print("&lt;%s>" % tag)
        return TreeBuilder.start(self, tag, attrs)

    def data(self, data):
        print(repr(data))
        TreeBuilder.data(self, data)

    def end(self, tag):
        return TreeBuilder.end(self, tag)

text = """<xml>
The captial of <place pid="1">South Africa</place> is <place>Pretoria</place>.
</xml>"""

# ElementTree.fromstring()
parser = XMLParser(target=MyTreeBuilder())
parser.feed(text)
root = parser.close() # return an ordinary Element

Вывод

<xml>
'\nThe captial of '
<place>
'South Africa'
' is '
<place>
'Pretoria'
'.\n'
14.11.2011
  • Это очень полезно. Спасибо! 16.11.2011

  • 2

    Вам нужно посмотреть на свойство .tail, а также на .text: .text дает вам текст сразу после начального тега, .tail дает вам текст сразу после конечного тега. Это даст вам «множество маленьких строк».

    Совет: вы можете использовать etree.iterwalk(elem) (делает то же самое, что и etree.iterparse(), но вместо этого над существующим деревом) для перебора начального и конечного тегов. К идее:

    for event, elem in etree.iterwalk(xml_elem, events=('start', 'end')):
        if event == 'start':
            # it's a start tag
            print 'starting element', elem.tag
            print elem.text
        elif event == 'end':
            # it's an end tag
            print 'ending element', elem.tag
            if elem is not xml_elem:
                # dont' want the text trailing xml_elem
                print elem.tail
    

    Я думаю, вы можете закончить остальное для себя? Предупреждение: .text и .tail могут быть None, поэтому, если вы хотите конкатенировать, вам придется защищаться от этого (например, используйте (elem.text or ''))

    Если вы знакомы с саксофоном (или у вас есть существующий саксофонный код, который делает то, что вам нужно), lxml позволяет вам -or-element" rel="nofollow">создавать события саксофона из элемента или дерева:

    lxml.sax.saxify(elem, handler)
    

    Некоторые другие вещи, на которые следует обратить внимание при извлечении всего текста из элемента: метод .itertext(), выражение xpath .//text() (lxml позволяет вам возвращать «умные строки» из выражений xpath: они позволяют вам проверить, какому элементу они принадлежат и т. д... ).

    13.11.2011
  • Спасибо! Это выглядит идеально, хотя я могу найти iterwalk только в lxml, а не в ElementTree, который идет в комплекте с Python. Я ищу в неправильном месте? 13.11.2011
  • Вы правы, это только в lxml. Извините, я так привык использовать lxml, что подумал, что вы тоже. (попробуйте, это здорово). Но вы должны быть в состоянии сделать что-то самостоятельно с помощью iter() 14.11.2011
  • elem.text может быть недоступен в event == 'start'. 14.11.2011
  • @Leon Derczynski: iterparse() доступен во всех версиях Python с xml.etree. 14.11.2011
  • @Дж.Ф. Себастьян: iterparse() есть, а iterwalk() есть только в lxml. 14.11.2011
  • Разве itertext() не дает вам просто весь текст, текстами и решками? 05.07.2016

  • 3

    (3) можно сделать с помощью XMLParser.CurrentByteIndex вот так:

    import xml.etree.ElementTree as ET
    
    class MyTreeBuilder(ET.TreeBuilder):
        def start(self, tag, attrs):
            print(parser.parser.CurrentByteIndex)
            ET.TreeBuilder.start(self, tag, attrs)
    
    builder = MyTreeBuilder()
    parser = ET.XMLParser(target=builder)
    builder.parser = parser
    tree = ET.parse('test.xml', parser=parser)
    

    См. также этот ответ для альтернативы SAX. Обратите внимание, однако, что индекс байта не совпадает с индексом символа, и в Python может не существовать эффективного способа преобразования индекса байта в символ. (См. также здесь.)

    Обходной путь (по общему признанию, уродливый) для получения смещений символов вместо смещений байтов состоит в том, чтобы перекодировать байты как символы. Предполагая, что фактическая кодировка utf8:

    import xml.etree.ElementTree as ET
    
    class MyTreeBuilder(ET.TreeBuilder):
        def start(self, tag, attrs):
            print(parser.parser.CurrentByteIndex)
            ET.TreeBuilder.start(self, tag, attrs)
    
    builder = MyTreeBuilder()
    parser = ET.XMLParser(target=builder)
    builder.parser = parser
    with open('test.xml', 'rb') as f:
        parser.feed(f.read().decode('latin1').encode('utf8'))
    
    10.08.2016

    4

    (2) легко с SAX, см. этот фрагмент

    from xml.sax.handler import ContentHandler
    import xml.sax
    import sys
    
    class textHandler(ContentHandler):
        def characters(self, ch):
            sys.stdout.write(ch.encode("Latin-1"))
    
    parser = xml.sax.make_parser()
    handler = textHandler()
    parser.setContentHandler(handler)
    parser.parse("test.xml")
    

    или пример 1-1: bookhandler.py в этой книге http://oreilly.com/catalog/pythonxml/chapter/ch01.html

    (3) сложнее, обратитесь к этому потоку, это Java, но в API Python SAX должна быть похожая вещь Как мне получить правильное начальное/конечное расположение тега xml с помощью SAX?

    13.11.2011
  • Спасибо! (2) и (3), безусловно, проще с SAX. В прошлый раз, когда у меня была эта проблема, я использовал и SAX, и minidom, но выравнивание результатов этих двух — проблема, к которой не стоит подходить. Я бы перешел на SAX, если бы мог сделать (1) достаточно легко. Знаете ли вы какие-либо подходы для этого? 13.11.2011
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..