提问人:Mark 提问时间:7/19/2023 最后编辑:Mark 更新时间:7/19/2023 访问量:55
使用 xpath 提取列表
Extracting a list of list with xpath
问:
我想使用 xpath 来获取列表(或序列序列)列表,该列表按父元素按顺序对提取的 xml 标签进行分组。
以下是我到目前为止使用最小示例的尝试。
import elementpath, lxml.etree
xml = '''<a>
<b c="1">
<d e="3"/>
<d e="4"/>
</b>
<b c="2">
<d e="5"/>
<d e="6"/>
</b>
</a>'''
tree = lxml.etree.fromstring(str.encode(xml))
xpath1 = '/a/b/d/@e'
xpath2 = 'for $b in (/a/b) return concat("[", $b/string-join(d/@e, ", "), "]")'
print('1:', elementpath.select(tree, xpath1))
print('2:', elementpath.select(tree, xpath2))
print('3:', [['3', '4'], ['5', '6']])
哪个输出..
1: ['3', '4', '5', '6']
2: ['[3, 4]', '[5, 6]']
3: [['3', '4'], ['5', '6']]
xpath1 返回一个扁平化的列表/序列,不按父元素分组。
xpath2 是我迄今为止最接近的,但以字符串而不是数组的形式提供子数组。
选项 3 是我所追求的
有人能够建议仅使用 xpath 的更好方法吗?
谢谢,马克
答:
0赞
Martin Honnen
7/19/2023
#1
ElementPath支持XPath 3.1和XPath / XDM数组,所以我认为你想要,就XPath而言
/a!array { b ! array { d/@e/string() } }
这应该给.[["3","4"],["5","6"]]
这是 SaxonC HE (12.3) 的输出
from saxonche import PySaxonProcessor
xml = '''<a>
<b c="1">
<d e="3"/>
<d e="4"/>
</b>
<b c="2">
<d e="5"/>
<d e="6"/>
</b>
</a>'''
with PySaxonProcessor(license=False) as saxon:
xdm_doc = saxon.parse_xml(xml_text=xml)
xpath_processor = saxon.new_xpath_processor()
xpath_processor.set_context(xdm_item=xdm_doc)
xdm_value = xpath_processor.evaluate_single('/a!array { b ! array { d/@e/string() } }')
print(xdm_value)
在那个阶段,您没有Python列表列表,但是,而是PyXdmItem,它是数组的XDM数组,要获得嵌套的Python列表,我认为您可以做到
list_of_lists = [inner_array.head.as_list() for inner_array in xdm_array.as_list()]
print(list_of_lists)
我需要检查 ElementPath 是否也允许这样做,也许更优雅一些;我发现的最简单的是
import elementpath, lxml.etree
from elementpath.xpath3 import XPath3Parser
xml = '''<a>
<b c="1">
<d e="3"/>
<d e="4"/>
</b>
<b c="2">
<d e="5"/>
<d e="6"/>
</b>
</a>'''
tree = lxml.etree.fromstring(str.encode(xml))
array_of_arrays = elementpath.select(tree, '/a!array { b ! array { d/@e/string() } }', parser=XPath3Parser)
print(array_of_arrays)
list_of_lists = [array.items() for array in array_of_arrays[0].items()]
print(list_of_lists)
为决赛付出.[['3', '4'], ['5', '6']]
pint(list_of_lists)
或者,在 XPath 中使用数组序列可以为您提供 Python 中的数组列表,您可以更轻松地将其转换为 Python 中的列表列表:
sequence_of_arrays = elementpath.select(tree, '/a/b ! array { d/@e/string() }', parser=XPath3Parser)
print(sequence_of_arrays)
list_of_lists = [array.items() for array in sequence_of_arrays]
print(list_of_lists)
评论
0赞
Mark
7/21/2023
谢谢你,完美!
评论
[x.xpath('d/@e') for x in tree.xpath('/a/b')]