Как обрабатывать Element.tail в lxml / elementtree .iter () - PullRequest
0 голосов
/ 23 февраля 2019

Думая о том, как работает следующая проблема с итерацией дерева, у меня в голове завязались узлы, которые, возможно, некоторые из вас помогут решить / развязать.

У меня есть (TEI) XML-тексты, и я хочу сегментировать их по <milestone>s.Чтобы обозначить сегменты, я хочу использовать атрибут <milestone> и одного из родительских элементов <div>.Я думаю, это означает, что я не могу использовать метод itertext(), потому что он не позволяет мне получить доступ к этим атрибутам при обработке текстовых узлов.Поэтому мой подход заключается в использовании метода iter(), подачи всего текстового содержимого в буфер и записи его в выходные сегменты (словарь меток и текстовое содержимое сегмента), когда я сталкиваюсь с элементом вехи.Когда я не в элементе вехи в итерации, я записываю .text существующего узла в мой буфер.

Трудная вещь в том, когда и как обрабатывать .tail текст: Когда я просто проверяю текущий узел на .tail и добавляю его в буфер, он появится перед .text дочерних узлов текущего узла (хотя в действительности он должен следовать после), и если я не проверю наэто, у меня никогда не будет другого шанса поймать это, или я ошибся?

Могу ли я вообще использовать lxml iter() или мне нужно создать свою собственную рекурсивную итерационную функцию?(Ранее я пытался сегментировать текст с помощью выражения XPath, но его производительность была недопустимой (> 24 ч).

Я извиняюсь за длинный и грязный фрагмент кода xml, но не могу понять, какие отрывки я мог быПриведите в порядок или пропустите этот вопрос. (И некоторые другие вопросы (например, this ) не применимы именно потому, что у меня более грязный xml.

Спасибо за любую помощь.

Код:

from typing import Dict
import lxml
from lxml import etree

def segment(chapter: lxml.etree._Element) -> Dict[str, str]:
    segments = {} # this will be returned
    t = []        # this is a buffer
    chap_label = str(chapter.get("n"))
    sect_label = "0"
    for element in chapter.iter():
        if element.get("unit")=="number":
            # milestone: fill and close the previous segment:
            label = chap_label + "_" + sect_label
            segments[label] = " ".join(t)
            # reset buffer
            t = []
            # if there is text after the milestone,
            # add it as first content to the buffer
            if element.tail:
                t.append(" ".join(str.replace(element.tail, "\n", " ").strip().split()))
            # prepare for next labelmaking
            sect_label = str(element.get("n"))
        else:
            if element.text:
                t.append(" ".join(str.replace(element.text, "\n", " ").strip().split()))
            if element.tail:
                t.append(" ".join(str.replace(element.tail, "\n", " ").strip().split()))
    # all elements are processed,
    # add text remainder/current text buffer content
    label = chap_label + "_" + sect_label
    segments[label] = " ".join(t)
    return segments

nsmap = {"tei": "http://www.tei-c.org/ns/1.0"}
xp_divs = etree.XPath("(//tei:body/tei:div)", namespaces = nsmap)

segmented = {}
divs = xp_divs(document)
segments = (segment(div) for div in divs)
for d in segments:
    print(d)

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

document=etree.fromstring("""
<TEI xmlns="http://www.tei-c.org/ns/1.0">
<text>
  <body>
    <div n="1">
      <p>
      ... <milestone unit="number" n="9"/>aun que el amor de Dios ha de ser
      grandissimo ..., como despues de. S. Tho.
      <ref target="#nm-0406">b</ref><note xml:id="nm-0406"><p>1. Sec. quaestio
      109. ar. 3.</p></note>, poco ha lo tratamos
      <ref target="#nm-0407">c</ref><note xml:id="nm-0407"><p>in addit. ca.
      Quoniam. de consec. disti. 1. nu. 10.</p></note>. Anadimos, (virtual)
      <milestone unit="number" n="10"/>porque aquella basta, ...
      <ref target="#nm-0408">d</ref><note xml:id="nm-0408"><p>in 4. dis. 14.
      q. 1. art. 3.</p></note>, que pone exemplo ..., que Gabriel sigue
      <ref target="#nm-0409">e</ref><note xml:id="nm-0409"><p>in 4. dis. 14.
      q. 1. col. 12. &amp; 13. &amp; in. 3. di. 27. q. 1. co. 15.</p></note>.
      <milestone unit="other" rendition="#asterisk"/> Y aun, aquel doctissimo,
      ... <ref target="#nm-040a">f</ref><note xml:id="nm-040a"><p>In Codice de
      poeni. q. 2.</p></note>, y con razon, ..., el martyrio atribuya esto
      <ref target="#nm-040b">g</ref><note xml:id="nm-040b"><p>Lib. 2. c. 16.
      de natu. &amp; gra.</p></note>, porque mas haze para esto el amor, ...
      que lo que se padece <ref target="#nm-040c">h</ref><note xml:id="nm-040c">
      <p>Arg. c. 13. 1. ad Corinth.</p></note>. Y puede ser que mas ame, ...,
      como lo prueua bien Medina
      <ref target="#nm-040d">i</ref><note xml:id="nm-040d"><p>in predi.
      q. 2.</p></note>. Por lo qual largamente paresce quan lexos esta esto
      dela opinion de Luthero<milestone unit="other" rendition="#asterisk"/>.
      De lo dicho se collige la razon, ..., segun Syluestro
      <ref target="#nm-040e">k</ref><note xml:id="nm-040e"><p>verb. Contritio.
      q. 1.</p></note>. Diximos <milestone unit="number" n="11"/> (auer
      pecado,) porque el arrepentimiento ...
      </p>
    </div>
  </body>
</text>
</TEI>""")

Результат (для удобочитаемости, обернуты и отображаются здесь как csv):

1_9,"aun que el amor de Dios ha de ser grandissimo ..., como despues
     de. S. Tho. b , poco ha lo tratamos 1. Sec. quaestio 109. ar. 3.
     c . Anadimos, (virtual) in addit. ca. Quoniam. de consec. disti.
     1. nu. 10."
1_10,"porque aquella basta, ... d , que pone exemplo ..., que Gabriel
      sigue in 4. dis. 14. q. 1. art. 3. e . in 4. dis. 14. q. 1. col.
      12. & 13. & in. 3. di. 27. q. 1. co. 15. Y aun, aquel doctissimo,
      ... f, y con razon, ..., el martyrio atribuya esto In Codice de
      poeni. q. 2. g , porque mas haze para esto el amor, ... que lo que
      se padece Lib. 2. c. 16. de natu. & gra. h . Y puede ser que mas
      ame, ..., como lo prueua bien Medina Arg. c. 13. 1. ad Corinth.
      i . Por lo qual largamente paresce quan lexos esta esto dela
      opinion de Luthero in predi. q. 2. . De lo dicho se collige la
      razon, ..., segun Syluestro k . Diximos verb. Contritio. q. 1."
1_11,"(auer pecado,) porque el arrepentimiento ..."

(Вы можете видеть, например, что содержание примечания nm-0408 должно идти после "porque aquella basta, ... d", но это приходит только позже, после "Que Gabriel sigue" ...)

...