首页 > 解决方案 > 如何处理 lxml/elementtree .iter() 中的 Element.tail

问题描述

思考以下树迭代问题的工作原理在我的脑海中打结,也许你们中的一些人可以帮助解决/解开。

我有(TEI)XML 文本,想用<milestone>s 分割它们。为了标记段,我想使用父元素之一的<milestone> 属性。<div>我认为这意味着我不能使用该itertext()方法,因为它不允许我在处理文本节点时访问这些属性。所以我的方法是使用该iter()方法,当我遇到里程碑元素时,将所有文本内容输入缓冲区并将其刷新到输出段(段的标签和文本内容的字典)中。当我不在迭代中的里程碑元素时,我.text将当前节点写入我的缓冲区。

困难的是何时以及如何处理.tail文本:当我只是测试当前节点.tail并将其附加到缓冲区时,它将出现在.text当前节点的子节点之前(实际上它应该出现在之后)如果我不'不要测试它,我再也没有机会抓住它,还是我弄错了?

我什至可以使用 lxmliter()还是必须构建自己的递归迭代函数?(我之前尝试通过 XPath 表达式对文本进行分段,但其性能无法接受(>24h)。

对于冗长而凌乱的 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”之后...)

标签: pythonlxmlelementtree

解决方案


推荐阅读