好吧,在 jQuery 的帮助下,我制作了这个适用于我的用例场景的替代 XPath 解析器。解析器试图停留在我的输入指定的 XPath 上,但是如果 DOM 模型在路径的中间添加了一个新标签,其中路径的其余部分被包裹在这个单个元素中,解析器会识别这个添加并包含这个单个元素进入路径。这当然不适用于每个人和每个用例场景,但它适用于我。也许这个解决方案对其他人有帮助,至少在一些扩展之后:
var SloppyXPathParser = (function () {
function childExists($cursor, element) {
assertSelection($cursor);
var $movedCursor = $cursor.children(element.name);
if ($movedCursor.size() > element.index) {
return jQuery($movedCursor.get(element.index));
} else if ($cursor.children().size() == 1) {
return childExists(jQuery($cursor.children().get(0)), element);
} else {
throw 'Cannot browse to \'' + element.name + '\' at index ' + element.index + '\'';
}
}
function assertSelection($cursor) {
if (!($cursor instanceof jQuery) || $cursor.size() != 1) {
throw 'Selection is invalid: ' + $cursor.size();
}
}
function parsePath(rawPath) {
var nodes = rawPath.split('/');
var regex = new RegExp('([a-zA-Z]+)\\[([0-9]+)\\]');
var elements = [];
var index = 0;
jQuery(nodes).each(function (key, element) {
if (element.length == 0) {
return true;
}
if (!regex.test(element)) {
throw 'Path element does not match regex: ' + element;
}
var matched = regex.exec(element);
elements[index++] = { name: matched[1], index: matched[2] };
});
return elements;
}
function findElement(input) {
var elements = parsePath(input);
var $cursor = jQuery(document);
jQuery(elements).each(function (key, element) {
$cursor = childExists($cursor, element);
});
try {
assertSelection($cursor);
} catch (cause) {
console.log('Exception: ' + cause);
return false;
}
return $cursor.get(0);
}
return {
find: function (input) {
return findElement(input);
}
}
})();
var input = '/html[0]/body[0]/table[0]/tr[1]/td[1]';
SloppyXPathParser.find(input);
HTML 源代码为:
<html>
<body>
<table>
<tr>
<td>wrong</td>
<td>wrong</td>
</tr>
<tr>
<td>wrong</td>
<td>right</td>
</tr>
</table>
</body>
</html>
您可以通过例如 Firebug 检查浏览器是否将tbody
元素添加到 DOM。解析器将识别这一点并跳过该条目。