使用 xpath 获取给定相邻节点文本的 XML 节点文本
Get text of XML node given text of adjacent node with xpath
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 并且有文本为英语的子字段我想要 link 在节点子字段代码="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
您的 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()
。例如,如果您只想检查文本 English
的 code
属性值为 "y" 的 subfield
元素,您可以这样做(这会导致谓词无效使用 findall()
时出错):
eng = root.xpath('.//s:datafield[@tag="856"][s:subfield[@code="y"]="English"]/s:subfield[@code="u"]', namespaces=ns)
此外,您处理名称空间的方式没有任何问题,但我发现将前缀映射到名称空间 uris 更容易;特别是当有多个命名空间时。
示例...
ns = {'s': 'http://www.loc.gov/MARC21/slim'}
eng = root.findall('.//s:datafield[@tag="856"][s:subfield="English"]/s:subfield[@code="u"]', namespaces=ns)
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 并且有文本为英语的子字段我想要 link 在节点子字段代码="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
您的 XPath 有几个问题。
首先,你不能在 /
.
[]
)
其次,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()
。例如,如果您只想检查文本 English
的 code
属性值为 "y" 的 subfield
元素,您可以这样做(这会导致谓词无效使用 findall()
时出错):
eng = root.xpath('.//s:datafield[@tag="856"][s:subfield[@code="y"]="English"]/s:subfield[@code="u"]', namespaces=ns)
此外,您处理名称空间的方式没有任何问题,但我发现将前缀映射到名称空间 uris 更容易;特别是当有多个命名空间时。
示例...
ns = {'s': 'http://www.loc.gov/MARC21/slim'}
eng = root.findall('.//s:datafield[@tag="856"][s:subfield="English"]/s:subfield[@code="u"]', namespaces=ns)