Mar*_*arc 40 html javascript xml jquery xpath
假设我有一个包含不同类型标签的大型HTML文件,类似于您现在正在查看的StackOverflow.
现在让我们说你单击页面上的一个元素,Javascript函数会是什么样的,它会计算引用该特定元素的最基本的XPath?
我知道在XPath中有一种无限的方式来引用该元素,但我正在寻找一些只关注DOM树的东西,而不考虑ID,类等.
例:
<html>
<head><title>Fruit</title></head>
<body>
<ol>
<li>Bananas</li>
<li>Apples</li>
<li>Strawberries</li>
</ol>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
假设您点击苹果.Javascript函数将返回以下内容:
/html/body/ol/li[2]
Run Code Online (Sandbox Code Playgroud)
它基本上只是向上运行DOM树一直到HTML元素.
只是为了澄清,'on-click'事件处理程序不是问题.我能做到这一点.我只是不确定如何计算元素在DOM树中的位置并将其表示为XPath.
PS赞赏使用或不使用JQuery库的任何答案.
PPS我对XPath完全不熟悉,所以我甚至可能在上面的例子中犯了一个错误,但你会明白这个想法.
编辑于2010年8月11日:看起来有人问了一个类似的问题:为选定的textnode生成/获取Xpath
Mat*_*hen 31
Firebug可以做到这一点,它是开源的(BSD),因此您可以重用它们的实现,这不需要任何库.
这是上面链接源的摘录.以防上述链接发生变化.请检查来源以获得更改和更新或提供的完整功能集.
Xpath.getElementXPath = function(element)
{
if (element && element.id)
return '//*[@id="' + element.id + '"]';
else
return Xpath.getElementTreeXPath(element);
};
Run Code Online (Sandbox Code Playgroud)
上面的代码调用此函数.注意我添加了一些换行以避免水平滚动条
Xpath.getElementTreeXPath = function(element)
{
var paths = []; // Use nodeName (instead of localName)
// so namespace prefix is included (if any).
for (; element && element.nodeType == Node.ELEMENT_NODE;
element = element.parentNode)
{
var index = 0;
var hasFollowingSiblings = false;
for (var sibling = element.previousSibling; sibling;
sibling = sibling.previousSibling)
{
// Ignore document type declaration.
if (sibling.nodeType == Node.DOCUMENT_TYPE_NODE)
continue;
if (sibling.nodeName == element.nodeName)
++index;
}
for (var sibling = element.nextSibling;
sibling && !hasFollowingSiblings;
sibling = sibling.nextSibling)
{
if (sibling.nodeName == element.nodeName)
hasFollowingSiblings = true;
}
var tagName = (element.prefix ? element.prefix + ":" : "")
+ element.localName;
var pathIndex = (index || hasFollowingSiblings ? "["
+ (index + 1) + "]" : "");
paths.splice(0, 0, tagName + pathIndex);
}
return paths.length ? "/" + paths.join("/") : null;
};
Run Code Online (Sandbox Code Playgroud)
JCD*_*JCD 18
我用来获取类似于你的情况的XPath的函数,它使用jQuery:
function getXPath( element )
{
var xpath = '';
for ( ; element && element.nodeType == 1; element = element.parentNode )
{
var id = $(element.parentNode).children(element.tagName).index(element) + 1;
id > 1 ? (id = '[' + id + ']') : (id = '');
xpath = '/' + element.tagName.toLowerCase() + id + xpath;
}
return xpath;
}
Run Code Online (Sandbox Code Playgroud)
imo*_*mos 11
它返回元素的xpath和xpath的元素迭代器.
https://gist.github.com/iimos/e9e96f036a3c174d0bf4
function xpath(el) {
if (typeof el == "string") return document.evaluate(el, document, null, 0, null)
if (!el || el.nodeType != 1) return ''
if (el.id) return "//*[@id='" + el.id + "']"
var sames = [].filter.call(el.parentNode.children, function (x) { return x.tagName == el.tagName })
return xpath(el.parentNode) + '/' + el.tagName.toLowerCase() + (sames.length > 1 ? '['+([].indexOf.call(sames, el)+1)+']' : '')
}
Run Code Online (Sandbox Code Playgroud)
可能你需要为不支持[] .filter方法的IE8添加一个垫片:这个MDN页面提供了这样的代码.
var xp = xpath(elementNode)
Run Code Online (Sandbox Code Playgroud)
执行xpath:
var iterator = xpath("//h2")
var el = iterator.iterateNext();
while (el) {
// work with element
el = iterator.iterateNext();
}
Run Code Online (Sandbox Code Playgroud)
可以稍微修改firebug实现以检查dom树中的element.id:
/**
* Gets an XPath for an element which describes its hierarchical location.
*/
var getElementXPath = function(element) {
if (element && element.id)
return '//*[@id="' + element.id + '"]';
else
return getElementTreeXPath(element);
};
var getElementTreeXPath = function(element) {
var paths = [];
// Use nodeName (instead of localName) so namespace prefix is included (if any).
for (; element && element.nodeType == 1; element = element.parentNode) {
var index = 0;
// EXTRA TEST FOR ELEMENT.ID
if (element && element.id) {
paths.splice(0, 0, '/*[@id="' + element.id + '"]');
break;
}
for (var sibling = element.previousSibling; sibling; sibling = sibling.previousSibling) {
// Ignore document type declaration.
if (sibling.nodeType == Node.DOCUMENT_TYPE_NODE)
continue;
if (sibling.nodeName == element.nodeName)
++index;
}
var tagName = element.nodeName.toLowerCase();
var pathIndex = (index ? "[" + (index+1) + "]" : "");
paths.splice(0, 0, tagName + pathIndex);
}
return paths.length ? "/" + paths.join("/") : null;
};
Run Code Online (Sandbox Code Playgroud)
我刚刚修改了DanS的解决方案,以便将它与textNodes一起使用.对序列化HTML范围对象非常有用.
/**
* Gets an XPath for an node which describes its hierarchical location.
*/
var getNodeXPath = function(node) {
if (node && node.id)
return '//*[@id="' + node.id + '"]';
else
return getNodeTreeXPath(node);
};
var getNodeTreeXPath = function(node) {
var paths = [];
// Use nodeName (instead of localName) so namespace prefix is included (if any).
for (; node && (node.nodeType == 1 || node.nodeType == 3) ; node = node.parentNode) {
var index = 0;
// EXTRA TEST FOR ELEMENT.ID
if (node && node.id) {
paths.splice(0, 0, '/*[@id="' + node.id + '"]');
break;
}
for (var sibling = node.previousSibling; sibling; sibling = sibling.previousSibling) {
// Ignore document type declaration.
if (sibling.nodeType == Node.DOCUMENT_TYPE_NODE)
continue;
if (sibling.nodeName == node.nodeName)
++index;
}
var tagName = (node.nodeType == 1 ? node.nodeName.toLowerCase() : "text()");
var pathIndex = (index ? "[" + (index+1) + "]" : "");
paths.splice(0, 0, tagName + pathIndex);
}
return paths.length ? "/" + paths.join("/") : null;
};
Run Code Online (Sandbox Code Playgroud)