1

我使用jQuery Xpath插件来浏览 HTML 文档的层次结构。我不使用选择器是因为我需要处理服务器端框架的信息,它告诉我特定元素的 Xpath。

现在我观察到 DOM 不一定代表 HTML 文档的层次结构,并在这里找到了解决此问题的方法:为什么 firebug 将 <tbody> 添加到 <table>?. 这意味着,如果我的 HTML 文档确实包含以下代码:

<table>
  <tr>
    <td>Hello</td>
  </tr>
</table>

我的 DOM 将像这样代表后者:

<table>
  <tbody>
    <tr>
      <td>Hello</td>
    </tr>
  </tbody>
</table>

我的 Xpath 查询

jQuery(document).xpath('//table[1]/tr[1]/td[1]')

因此不再产生结果。

有没有办法避免 DOM 表示的合成元素?还是一种调整 Xpath 使其包含合成元素的方法?谢谢你的帮助。

4

3 回答 3

1

好吧,在 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。解析器将识别这一点并跳过该条目。

于 2013-07-18T08:25:47.360 回答
0

如果您没有任何嵌套表,jQuery(document).xpath('//table[1]//tr[1]/td[1]')则应该在这两种情况下都可以使用。

在更一般的情况下,您可以适应如何选择孩子或自我(孩子+自我)的答案

在 XPath 1.0 中,这将转换为jQuery(document).xpath('(//table|//table/tbody)/tr[1]/td[1]')或更一般地转换为jQuery(document).xpath('(//table|//table/node())/tr[1]/td[1]')

于 2013-07-17T15:27:07.680 回答
0

只需将您的单曲/变成双曲tr

//table[1]/tr[1]/td[1]->//table[1]//tr[1]/td[1]

这将匹配初始表格标签下方任意深度的表格行,因此您可以添加任意数量的<tbody>标签。

于 2013-07-18T09:11:40.603 回答