You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用XPath获取并分组两个空pb节点间的所有节点与文本?

这是个非常实际的需求!要实现按<pb/>节点分组抓取内容,得根据你使用的XPath版本来选方案,下面分两种常见情况说明:

XPath 2.0及以上版本(推荐)

XPath 2.0+支持循环和更灵活的节点序列处理,直接用for表达式就能轻松分组:

for $pb in //pb
return $pb/following-sibling::node()[not(preceding-sibling::pb[. >> $pb])]

逻辑解释:

  1. $pb in //pb 遍历所有<pb/>节点;
  2. following-sibling::node() 取当前<pb/>之后的所有兄弟节点(包括文本节点、元素节点,比*更全面);
  3. not(preceding-sibling::pb[. >> $pb]) 过滤掉那些在下一个<pb/>之后的节点——简单说就是只保留到下一个<pb/>出现前的内容,最后一个<pb/>则会保留到文档末尾的所有内容。

这样每个<pb/>对应的结果就是你要的分组,完美匹配示例里的Group1、Group2、Group3。

XPath 1.0版本(兼容性方案)

XPath 1.0没有原生的循环和分组功能,得结合宿主语言(比如XSLT、Python的lxml、Java的DOM等)来实现。这里用Python+lxml举个实际例子:

from lxml import etree

# 加载XML文档
tree = etree.parse("your_xml_file.xml")
# 获取所有<pb/>节点的列表
pb_nodes = tree.xpath("//pb")

# 循环处理每个<pb/>对应的分组
for idx, current_pb in enumerate(pb_nodes):
    if idx < len(pb_nodes) - 1:
        # 不是最后一个<pb/>,取到下一个<pb/>之前的内容
        group = current_pb.xpath("""
            following-sibling::node()[
                count(preceding-sibling::pb) = count(current()/preceding-sibling::pb) + 1
            ]
        """)
    else:
        # 最后一个<pb/>,取到文档末尾的所有内容
        group = current_pb.xpath("following-sibling::node()")
    
    # 输出分组内容(这里可以换成你自己的处理逻辑)
    print(f"=== Group {idx+1} ===")
    for node in group:
        print(etree.tostring(node, encoding="unicode").strip())

XPath 1.0表达式逻辑:

count(preceding-sibling::pb) = count(current()/preceding-sibling::pb) + 1 意思是:当前节点前面的<pb/>数量,正好比当前<pb/>前面的<pb/>数量多1——这就保证了节点是在当前<pb/>之后、下一个<pb/>之前的范围里。

额外注意点

  • 如果<pb/>不是同一父节点的兄弟节点(比如嵌套在不同元素里),把following-sibling::node()换成following::node(),同时调整过滤条件避免跨层级的<pb/>干扰;
  • 如果不需要注释、处理指令这类节点,可以在表达式里加not(self::comment()) and not(self::processing-instruction())来过滤;
  • 文本节点会被完整保留,包括空白字符,要是需要清理可以在宿主语言里做额外处理。

内容的提问来源于stack exchange,提问作者zypro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:42:23