如何用XPath实现按divider分组提取相邻<p>元素集合?
按分组提取
元素的XPath方案
核心思路
无需硬编码节点位置,通过每个
元素的前置
方案1:XPath 2.0+(原生支持分组)
如果你的XPath引擎支持2.0及以上版本(如Saxon、XQuery处理器),可直接利用循环和节点位置运算符实现:
let $root := //root, $dividers := ($root/divider, $root/node()[last()]) order by $dividers/position() for $i in 1 to count($dividers) return if ($i = 1) then $root/p[not(preceding-sibling::divider)] else $root/p[preceding-sibling::divider[1] = $dividers[$i-1] and . << $dividers[$i]]
逻辑说明
- 收集所有
节点和文档末尾节点作为分隔边界 - 遍历每个边界区间,提取对应范围内的
元素
- 单独处理第一个区间(无前置
的 )
方案2:XPath 1.0 + 宿主语言(以Python为例)
XPath 1.0不支持原生循环和分组,需结合宿主语言逻辑实现,以下是基于Python lxml库的示例:
步骤分解
- 获取所有分隔节点
//divider
- 分区间提取
- 提取第一个
之前的 :
//p[not(preceding-sibling::divider)]
- 提取两个
之间的 (需传入当前和下一个
作为参数):
following-sibling::p[preceding-sibling::divider[1] = $current_div and following-sibling::divider[1] = $next_div]
- 提取最后一个
之后的 :
following-sibling::p[preceding-sibling::divider[1] = $last_div]
完整代码示例
from lxml import etree # 示例XML结构 xml_content = """ <root> <p>第一组段落1</p> <p>第一组段落2</p> <divider/> <p>第二组段落1</p> <divider/> <p>第三组段落1</p> <p>第三组段落2</p> </root> """ tree = etree.fromstring(xml_content) dividers = tree.xpath("//divider") result_groups = [] # 处理第一组(无前置分隔符的段落) first_group = tree.xpath("//p[not(preceding-sibling::divider)]") if first_group: result_groups.append([elem.text.strip() for elem in first_group]) # 处理分隔符之间的段落组 for idx, curr_div in enumerate(dividers): next_div = dividers[idx+1] if idx+1 < len(dividers) else None if next_div: group = curr_div.xpath( "following-sibling::p[preceding-sibling::divider[1] = $curr and following-sibling::divider[1] = $next]", curr=curr_div, next=next_div ) else: # 处理最后一个分隔符后的段落 group = curr_div.xpath( "following-sibling::p[preceding-sibling::divider[1] = $curr]", curr=curr_div ) if group: result_groups.append([elem.text.strip() for elem in group]) print(result_groups) # 输出: [['第一组段落1', '第一组段落2'], ['第二组段落1'], ['第三组段落1', '第三组段落2']]
关键细节
- 用
preceding-sibling::divider[1]定位每个的最近前置分隔符,完全避免硬编码位置
- XPath 2.0+方案更简洁,适合无需宿主语言介入的场景
- XPath 1.0方案兼容性更强,适配大多数旧版XML解析库
内容的提问来源于stack exchange,提问作者James Baker
相关产品推荐
相关产品推荐

