You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何lxml的XPath获取属性值有时返回列表?如何获取无引号值?

问题:lxml XPath获取属性返回类型不一致的解决办法

XML文档示例

<root>

<tok lemma="A" xpos="AQ0MS00">sobredit</tok>
<tok lemma="B" xpos="Fc"> this </tok>
<tok lemma="something" xpos="AQ0MS00">something</tok>
<tok lemma="X" xpos="Fc"> that </tok>
<tok>del
  <dtok form="de" lemma="de" xpos="SPC00"/>
  <dtok form="el" lemma="el" xpos="DA0MS0"/>
</tok> 
<tok lemma="sobredit" xpos="AQ0MS00">sobredit </tok>
<tok lemma="X" xpos="Fc"> sometinelse </tok>

</root>

原Python代码

for el in root_element.xpath('//tok[starts-with(@xpos, "AQ")]'):
    if el.xpath('preceding::tok[1]/dtok'):
        prec_lem = el.xpath('preceding::tok[1]/dtok[last()]/@lemma')
    elif el.xpath('preceding::tok[1]'):
        prec_lem = el.xpath('preceding::tok[1]')[0].get('lemma')
    else:
        prec_lem = 'None'

遇到的问题

第一个条件满足时,prec_lem返回列表(比如['DA0MS0']);第二个条件满足时返回字符串。尝试用el.xpath('preceding::tok[1]/dtok[last()]').get('lemma')时触发AttributeError: 'list' object has no attribute 'get'错误,想知道两种XPath返回类型不同的原因,以及如何统一获取不带引号的属性值。

原因解释

  • 当XPath表达式直接定位到属性(比如@lemma)时,lxml的xpath()方法会返回所有匹配到的属性值组成的列表,哪怕只有一个匹配结果,也会放在列表里。
  • 当XPath表达式定位到元素节点(比如preceding::tok[1])时,xpath()方法返回的是匹配到的元素节点列表,你通过[0]取第一个元素后,调用get('lemma')方法,这个方法会直接返回该元素的属性值字符串(如果属性存在)。

解决方法

统一处理成字符串格式,有两种可行方式:

方式一:对属性列表取第一个元素

修改第一个条件里的代码:

prec_lem = el.xpath('preceding::tok[1]/dtok[last()]/@lemma')[0]

因为前面已经通过if el.xpath('preceding::tok[1]/dtok')确认了存在对应的dtok元素,所以[0]不会触发索引越界错误。

方式二:先取元素节点再用get方法

先获取dtok元素节点,再调用get方法:

dtok_el = el.xpath('preceding::tok[1]/dtok[last()]')[0]
prec_lem = dtok_el.get('lemma')

同样,前面的条件已经确认元素存在,所以[0]是安全的。

统一后的完整代码

for el in root_element.xpath('//tok[starts-with(@xpos, "AQ")]'):
    if el.xpath('preceding::tok[1]/dtok'):
        # 方式一:直接取属性列表的第一个元素
        prec_lem = el.xpath('preceding::tok[1]/dtok[last()]/@lemma')[0]
        # 或者方式二:先取元素再get属性
        # dtok_el = el.xpath('preceding::tok[1]/dtok[last()]')[0]
        # prec_lem = dtok_el.get('lemma')
    elif el.xpath('preceding::tok[1]'):
        prec_lem = el.xpath('preceding::tok[1]')[0].get('lemma')
    else:
        prec_lem = 'None'

内容的提问来源于stack exchange,提问作者jfontana

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 14:55:19