为何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
相关产品推荐
相关产品推荐

