如何在lxml中使用XPath忽略非内容元素

问题描述 投票:0回答:1

我正在尝试处理一堆 XML 文件,并在满足某些条件时向特定元素添加某些属性。我有相同 XML 文档的不同版本。其中一些有一些标签用于提供格式信息。这是一个例子:

  <tok id="w-47692" ord="96" lemma="bové" xpos="VMIP3S0">Bové</tok>
  <space/>
  <add>
    <tok form="Bernadó" id="w-47693" ord="97" lemma="bernadó" xpos="NP00000">Bernadó</tok>
  </add>
  <add>
    <tok id="w-47694" ord="98" lemma="mayor" xpos="NCMS000">Mayor</tok>
  </add>
  <tok id="w-47695" ord="99" lemma="ferran" xpos="NP00000">Ferran</tok>

标签

<space/>
表示原始文档(XML 文档是其表示形式)有一个空格。标签
<add> </add>
表明这些标签之间出现的内容不是原稿的一部分。 XML 文档的其他版本已清除这些格式元素:

  <tok form="Bernadó" id="w-47693" ord="97" lemma="bernadó" xpos="NP00000">Bernadó</tok>
  <tok id="w-47694" ord="98" lemma="mayor" xpos="NCMS000">Mayor</tok>
  <tok id="w-47695" ord="99" lemma="ferran" xpos="NP00000">Ferran</tok>

我遇到的问题是脚本在处理两个文档时产生不同的结果。这是两个输出:

  <add>
    <tok form="Bernadó" id="w-47693" ord="97" lemma="bernadó" xpos="NP00000">Bernadó</tok>
  </add>
  <add>
    <tok id="w-47694" ord="98" lemma="mayor" xpos="NCMS000">Mayor</tok>
  </add>
  <tok form="Bernadó" id="w-47693" ord="97" lemma="bernadó" xpos="NP0000">Bernadó</tok>
  <tok form="Mayor" id="w-47694" ord="98" lemma="Major" xpos="NP0000">Mayor</tok>

我没有包含我正在使用的整个脚本,因为它相当复杂,但这是脚本相关部分的简化版本:

def fix_matching_toks(tok):
    """
    Fix matching tokens by setting their lemma and xpos attributes.
    """
    preceding_tok = tok.xpath("preceding-sibling::tok[1]")
    if preceding_tok:
        
        preceding_tok_last_dtok = preceding_tok[0].xpath("./dtok[last()]")
    else:
        preceding_tok_last_dtok = None
    

    if tok.tag == "tok":
        if preceding_tok and preceding_tok[0].get("xpos") is not None and preceding_tok[0].get("xpos", "").startswith("NP"):
                tok.set("lemma", "Major")
                tok.set("xpos", "NP00000")

在我看来,发生的情况是相关 tok 元素周围的标签阻止 XPath 表达式与预期元素匹配。我认为 XPath 表达式

xpath("preceding-sibling::tok[1]")
会匹配前面的 tok 元素,无论是否有元素介入,但很明显事实并非如此。

如何防止这种情况发生?我希望所有 XML 文档都以相同的方式进行处理,无论它们是否包含这些介入的“无关”元素。

python xml xpath lxml
1个回答
0
投票

我在 XPath 中看到 2 选项:

简单一个(但可能更慢):

preceding::tok[1]

复杂一个(但可能更快)

  parent::add/preceding-sibling::*[1][self::add[tok]]/tok
| parent::add/preceding-sibling::*[1][self::tok]
| preceding-sibling::*[1][self::add[tok]]/tok
| preceding-sibling::*[1][self::tok]
© www.soinside.com 2019 - 2024. All rights reserved.