使用 xpath 提取列表

Extracting a list of list with xpath

提问人:Mark 提问时间:7/19/2023 最后编辑:Mark 更新时间:7/19/2023 访问量:55

问:

我想使用 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 的更好方法吗?

谢谢,马克

python xpath xpath-2.0

评论

0赞 larsks 7/19/2023
是否要求结果直接来自 xpath 表达式?因为给你你想要的。[x.xpath('d/@e') for x in tree.xpath('/a/b')]
0赞 Mark 7/19/2023
谢谢你的建议..我正在使用 XPaths 来配置 XML 解析器,并希望避免在解析器配置数据中使用 Python 代码

答:

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
谢谢你,完美!