提问人:lonix 提问时间:9/19/2023 最后编辑:lonix 更新时间:9/20/2023 访问量:48
XPath 以第一个祖先标记为目标
XPath to target first ancestor tag
问:
一些 HTML:
<div>
<div>
<button>
<svg xmlns="http://www.w3.org/2000/svg">
<path d="x" />
</svg>
</button>
</div>
<div>
<button> <!-- I want this -->
<svg xmlns="http://www.w3.org/2000/svg">
<path d="y" /> <!-- I have this -->
</svg>
</button>
</div>
</div>
我有数据()来定位第二个,然后我想得到它的祖先。y
path
button
我可以像这样定位元素:path
//svg/path[@d='y']
但我不能瞄准它最近的祖先:button
//svg/path[@d='y']/ancestor::button
如果我在 firefox 或 chromium devtools 中尝试这样做(对于包含上述标记的页面):
$x("//ancestor::button[1]", document.querySelector("path[d='y']"))
...它返回许多结果,而不仅仅是第一个祖先按钮。
答:
1赞
Jack Fleeting
9/19/2023
#1
你正在与命名空间纠缠不清。
处理此问题的一种方法是将 xpath 更改为
//svg[*[local-name()='path'][@d='y']]/parent::*[local-name()='button']
看看它是否有效。
评论
0赞
Siebe Jongebloed
9/19/2023
我认为svg也应该匹配吗?我怀疑按钮是否需要通过 匹配,因为它是 html。*[local-name()='svg']
local-name()
0赞
Jack Fleeting
9/19/2023
@SiebeJongebloed我想这取决于你的环境;我使用与 OP 相同的演示站点对其进行了测试,它的工作方式与答案中的相同,同时从失败中消除。没有领带去尝试其他任何事情。local-name()
button
0赞
Siebe Jongebloed
9/19/2023
演示站点显示您的 XPath 和注释是正确的。我仍然怀疑这是否正确。
0赞
lonix
9/20/2023
它适用于演示站点。但不是在浏览器中:返回一个空数组。我会摆弄它,看看我是否能让它工作。谢谢你给我一些工作!$x("//svg[*[local-name()='path'][@d='y']]/parent::*[local-name()='button']")
0赞
Jack Fleeting
9/20/2023
@lonix 你能发布链接吗?
2赞
Martin Honnen
9/20/2023
#2
在浏览器内部,并具有内置的 XPath 1.0 支持,我认为您需要使用命名空间来选择 SVG 元素,例如
var namespaceResolver = function(prefix) {
if (prefix === 'svg')
return 'http://www.w3.org/2000/svg';
else
return null;
}
var path = document.evaluate('//svg:svg/svg:path[@d = "y"]', document, namespaceResolver, XPathResult.FIRST_ORDERED_NODE_TYPE).singleNodeValue;
var ancestorButton = document.evaluate('ancestor::button[1]', path, namespaceResolver, XPathResult.FIRST_ORDERED_NODE_TYPE).singleNodeValue;
console.log(ancestorButton.outerHTML);
<div>
<div>
<button>
<svg xmlns="http://www.w3.org/2000/svg">
<path d="x" />
</svg>
</button>
</div>
<div>
<button> <!-- I want this -->
<svg xmlns="http://www.w3.org/2000/svg">
<path d="y" /> <!-- I have this -->
</svg>
</button>
</div>
</div>
或者切换到 SaxonJS 和 XPath 3.1,例如,在查找 SVG 和 HTML 元素时使用不同的默认元素命名空间,例如
const xhtmlNamespace = 'http://www.w3.org/1999/xhtml';
const svgNamespace = 'http://www.w3.org/2000/svg';
var path = SaxonJS.XPath.evaluate('//svg/path[@d = "y"]', document, { xpathDefaultNamespace : svgNamespace });
var ancestorButton = SaxonJS.XPath.evaluate('ancestor::button[1]', path, { xpathDefaultNamespace : xhtmlNamespace });
console.log(ancestorButton.outerHTML);
<script src="https://martin-honnen.github.io/Saxon-JS-2.5/SaxonJS2.js"></script>
<div>
<div>
<button>
<svg xmlns="http://www.w3.org/2000/svg">
<path d="x" />
</svg>
</button>
</div>
<div>
<button> <!-- I want this -->
<svg xmlns="http://www.w3.org/2000/svg">
<path d="y" /> <!-- I have this -->
</svg>
</button>
</div>
</div>
评论
xidel
//svg
svg
$x("//ancestor::button[1]", document.querySelector("path[d='y']"))
$x("ancestor::button[1]", document.querySelector("path[d='y']"))