给定具有xpath的相邻节点的文本,获取XML节点的文本

时间:2018-06-21 16:16:46

标签: python xml xpath lxml

关于SO的几篇文章对您有所帮助,但我还没有找到可以解决此特定问题的文章。

我正在使用python3和lxml.etree

给出XML:

<collection xmlns="http://www.loc.gov/MARC21/slim">
<record>
<datafield tag="856" ind1="4" ind2=" ">
<subfield code="y">English</subfield>
<subfield code="s">387115</subfield>
<subfield code="u">
http://some_url/record/1475606/files/COOLPDF-EN.pdf
</subfield>
</datafield>
</record>
</collection>

一个集合包含几百个记录和几十个数据字段(这都是国会图书馆非常神秘的东西)

如果数据字段具有标签856,并且子字段具有文本English,则我希望链接的文本位于节点子字段code =“ u”。

我尝试过:

import lxml.etree as ET
ns = '{http://www.loc.gov/MARC21/slim}'
tree = ET.parse('example.xml')
root = tree.getroot()
eng = root.findall(
    './/{0}datafield[@tag="856"]/[{0}descendant::text="English"]/[{0}following-sibling::code="u"]'.format(ns))
print([e.text for e in eng])

但这给我一个空的名单。

感谢您的帮助。

TIA

1 个答案:

答案 0 :(得分:2)

您的XPath有几个问题。

首先,您不能在[]之后直接放置predicate/)。

第二,descendant::text选择一个名为text的后代元素(XML中没有该元素)。同样,following-sibling::code正在选择名为code的元素,而不是属性。

尝试以下方法:

eng = root.findall('.//{0}datafield[@tag="856"][{0}subfield="English"]/{0}subfield[@code="u"]'.format(ns))

如果要使用更复杂的XPath,请改用xpath()。例如,如果您只想检查文本subfield的{​​{1}}属性值为“ y”的code元素,则可以这样做(这会导致无效谓词错误,使用English):

findall()

此外,您如何处理名称空间也没有错,但是我发现将前缀映射到名称空间uris更容易。尤其是在有多个名称空间的情况下。

示例...

eng = root.xpath('.//s:datafield[@tag="856"][s:subfield[@code="y"]="English"]/s:subfield[@code="u"]', namespaces=ns)