不使用distinct-values(),如何在各library内筛选唯一title的book元素?
实现每个Library内保留首个唯一Title的Book元素的XPath方案
兼容XPath 1.0的解决方案
如果你的CMS仅支持XPath 1.0,可使用以下表达式:
//library//book[count(ancestor::library//book[title = current()/title and generate-id(.) < generate-id(current())]) = 0]
表达式解释
//library//book:匹配所有<library>节点下任意层级的<book>元素ancestor::library//book:将检查范围严格限定在当前<book>所属的<library>内部,只对比该library内的其他booktitle = current()/title:筛选出和当前book拥有相同title的节点generate-id(.) < generate-id(current()):通过节点ID判断该节点在文档中的顺序早于当前bookcount(...) = 0:当满足条件的前置节点数量为0时,说明当前book是该library内该title的首次出现,会被选中
为什么你的原有写法不生效
你之前使用的//library//book[not(./title = preceding::*/title)]会匹配整个文档中所有在当前节点之前的元素的title,包括其他library里的节点。比如第二个library的首个ABC会被过滤,因为第一个library里已经存在相同的title。而上面的表达式通过ancestor::library把检查范围限制在当前book所属的library内部,避免了跨library的干扰。
简化场景的替代写法
如果你的<book>元素都是直接作为<library>的子节点(没有嵌套在其他元素下),可以用更简洁的表达式:
//library/book[not(title = preceding-sibling::book/title)]
这个写法利用preceding-sibling轴直接匹配当前book的同级前置book,同样能实现需求,但仅适用于book是library直接子节点的场景。
内容的提问来源于stack exchange,提问作者Alexis P.
相关产品推荐
相关产品推荐

