代码之家  ›  专栏  ›  技术社区  ›  The Archetypal Paul

相当于Internet Explorer中Firebug的“复制xpath”?

  •  12
  • The Archetypal Paul  · 技术社区  · 16 年前

    我有一个仅限Internet Explorer的Web应用程序。

    我正在探索我们可以做些什么来自动化测试。

    硒看起来是一个很好的工具,但是为了能够激活链接等,我需要告诉它它们在哪里。应用程序的构建并没有考虑到这种测试,因此通常没有 id 关键元素的属性。

    没问题,我想我可以使用xpath表达式。但是,如果通过检查页面的源代码来找到正确的xpath(比如按钮),那将是一种极大的痛苦。

    使用firefox/firebug,我可以选择元素,然后使用“copy xpath”获取表达式。

    我有IE开发者工具栏,它关闭得令人沮丧。我可以单击选择感兴趣的元素并显示有关它的各种信息。但我看不到任何方便的方法来确定它的xpath。

    有什么办法可以和IE一起做吗?

    3 回复  |  直到 7 年前
        1
  •  7
  •   PhiLho    15 年前

    我会用书签。我有一个与xpath相关的,但我不知道它在IE中是否有效。我得走了,但我会测试它,如果它在IE上有效的话,我会给出它。

    从我的书签中为Web开发人员提供两个书签网站: Subsimple's bookmarklets Squarefree's Bookmarklets . 那里有很多有用的东西…

    [编辑]好的,我回来了。我买的书签只是FF的,不是最理想的。我最终重写了它,尽管使用了原作中的思想。找不到我找到它的地方。

    扩展JS:

    function getNode(node)
    {
      var nodeExpr = node.tagName;
      if (nodeExpr == null)  // Eg. node = #text
        return null;
      if (node.id != '')
      {
        nodeExpr += "[@id='" + node.id + "']";
        // We don't really need to go back up to //HTML, since IDs are supposed
        // to be unique, so they are a good starting point.
        return "/" + nodeExpr;
      }
    // We don't really need this
    //~   if (node.className != '')
    //~   {
    //~     nodeExpr += "[@class='" + node.className + "']";
    //~   }
      // Find rank of node among its type in the parent
      var rank = 1;
      var ps = node.previousSibling;
      while (ps != null)
      {
        if (ps.tagName == node.tagName)
        {
          rank++;
        }
        ps = ps.previousSibling;
      }
      if (rank > 1)
      {
        nodeExpr += '[' + rank + ']';
      }
      else
      {
        // First node of its kind at this level. Are there any others?
        var ns = node.nextSibling;
        while (ns != null)
        {
          if (ns.tagName == node.tagName)
          {
            // Yes, mark it as being the first one
            nodeExpr += '[1]';
            break;
          }
          ns = ns.nextSibling;
        }
      }
      return nodeExpr;
    }
    
    var currentNode;
    // Standard (?)
    if (window.getSelection != undefined) 
      currentNode = window.getSelection().anchorNode;
    // IE (if no selection, that's BODY)
    else 
      currentNode = document.selection.createRange().parentElement();
    if (currentNode == null)
    {
      alert("No selection");
      return;
    }
    var path = [];
    // Walk up the Dom
    while (currentNode != undefined)
    {
      var pe = getNode(currentNode);
      if (pe != null)
      {
        path.push(pe);
        if (pe.indexOf('@id') != -1)
          break;  // Found an ID, no need to go upper, absolute path is OK
      }
      currentNode = currentNode.parentNode;
    }
    var xpath = "/" + path.reverse().join('/');
    alert(xpath);
    // Copy to clipboard
    // IE
    if (window.clipboardData) clipboardData.setData("Text", xpath);
    // FF's code to handle clipboard is much more complex 
    // and might need to change prefs to allow changing the clipboard content.
    // I omit it here as it isn't part of the original request.
    

    您必须选择元素并激活bookmarklet以获取其xpath。

    现在,书签版本(感谢 Bookmarklet Builder ):

    工业工程
    (我不得不把它分成两部分,因为IE不喜欢很长的书签(最大尺寸因IE版本而异!)。您必须先激活第一个(功能定义),然后激活第二个。用IE6测试。)

    javascript:function getNode(node){var nodeExpr=node.tagName;if(!nodeExpr)return null;if(node.id!=''){nodeExpr+="[@id='"+node.id+"']";return "/"+nodeExpr;}var rank=1;var ps=node.previousSibling;while(ps){if(ps.tagName==node.tagName){rank++;}ps=ps.previousSibling;}if(rank>1){nodeExpr+='['+rank+']';}else{var ns=node.nextSibling;while(ns){if(ns.tagName==node.tagName){nodeExpr+='[1]';break;}ns=ns.nextSibling;}}return nodeExpr;}
    javascript:function o__o(){var currentNode=document.selection.createRange().parentElement();var path=[];while(currentNode){var pe=getNode(currentNode);if(pe){path.push(pe);if(pe.indexOf('@id')!=-1)break;}currentNode=currentNode.parentNode;}var xpath="/"+path.reverse().join('/');clipboardData.setData("Text", xpath);}o__o();
    

    FF

    javascript:function o__o(){function getNode(node){var nodeExpr=node.tagName;if(nodeExpr==null)return null;if(node.id!=''){nodeExpr+="[@id='"+node.id+"']";return "/"+nodeExpr;}var rank=1;var ps=node.previousSibling;while(ps!=null){if(ps.tagName==node.tagName){rank++;}ps=ps.previousSibling;}if(rank>1){nodeExpr+='['+rank+']';}else{var ns=node.nextSibling;while(ns!=null){if(ns.tagName==node.tagName){nodeExpr+='[1]';break;}ns=ns.nextSibling;}}return nodeExpr;}var currentNode=window.getSelection().anchorNode;if(currentNode==null){alert("No selection");return;}var path=[];while(currentNode!=undefined){var pe=getNode(currentNode);if(pe!=null){path.push(pe);if(pe.indexOf('@id')!=-1)break;}currentNode=currentNode.parentNode;}var xpath="/"+path.reverse().join('/');alert(xpath);}o__o();
    
        2
  •  3
  •   community wiki PhiLho    16 年前

    既然书签使用了迷惑不解的保罗,我想我应该对他们的使用加一点介绍。我在一个单独的信息中这样做是为了避免混淆东西。

    书签(也称为favlets)是一种小的javascript脚本(sic),设计用于粘贴到浏览器的地址栏中(与任何其他URL一样),从而在当前页面上运行。
    运行它之后(粘贴,点击回车),你可以将它添加到书签中重新使用(添加到IE的收藏夹中)。请注意,浏览器可能会将原始URL添加为书签,然后您必须编辑书签并用脚本替换该URL。
    当然,您也可以将其添加到URL栏,以便快速访问。

    这些脚本就像是当前页面的一部分,访问全局JS变量和函数、DOM对象等。
    它们可以非常简单,就像种子一样 javascript: alert("Hello world!"); 或者像上面的那个很复杂。如果返回值(或者最后一个表达式有值),则该值将替换当前页。为了避免这种情况,您可以使用 alert (显示结果)或将脚本包装在函数定义中并调用此函数,就像上面所做的那样。(有些人还把空(0)放在最后,但我认为这被视为不好的做法。)

    函数解决方案的优点是使脚本的所有变量都成为小程序的本地变量(如果用 var 当然),避免与本地页面上的脚本发生干扰/副作用。这也是为什么包装函数的名称不可能与本地脚本冲突的原因。

    请注意,有些浏览器(读作“ie”)可以限制favlet的大小,其最大长度随版本而变化(趋于减小)。这就是为什么所有无用的空白都被删除的原因(上面链接的bookmarlet构建器很好地解决了这个问题),并且我删除了与空值和未定义值的显式比较,我通常这样做。我还必须将favlet分为两部分,第一部分定义一个函数(只要页面没有更改/刷新就活),第二部分使用它。

    非常有用的工具,特别是在不允许用户脚本(_la greasemonkey)或没有此扩展的浏览器上。

        3
  •  2
  •   Pěna    14 年前

    我已经把书签代码改写成了C,所以如果你觉得它有用,就用它;-)

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Text;
    
    namespace Anotation.Toolbar
    {
        class XPath
        {
            public static string getXPath(mshtml.IHTMLElement element)
            {
                if (element == null)
                    return "";
                mshtml.IHTMLElement currentNode = element;
                ArrayList path = new ArrayList();
    
                while (currentNode != null)
                {
                    string pe = getNode(currentNode);
                    if (pe != null)
                    {
                        path.Add(pe);
                        if (pe.IndexOf("@id") != -1)
                            break;  // Found an ID, no need to go upper, absolute path is OK
                    }
                    currentNode = currentNode.parentElement;
                }
                path.Reverse();
                return join(path, "/");
            }
    
            private static string join(ArrayList items, string delimiter)
            {
              StringBuilder sb = new StringBuilder();
              foreach (object item in items)
              {
                if (item == null)
                    continue;
    
                sb.Append(delimiter);
                sb.Append(item);
              }
              return sb.ToString();
            }
    
            private static string getNode(mshtml.IHTMLElement node)
            {
                string nodeExpr = node.tagName;
                if (nodeExpr == null)  // Eg. node = #text
                    return null;
                if (node.id != "" && node.id != null)
                {
                    nodeExpr += "[@id='" + node.id + "']";
                    // We don't really need to go back up to //HTML, since IDs are supposed
                    // to be unique, so they are a good starting point.
                    return "/" + nodeExpr;
                }
    
                // Find rank of node among its type in the parent
                int rank = 1;
                mshtml.IHTMLDOMNode nodeDom = node as mshtml.IHTMLDOMNode;
                mshtml.IHTMLDOMNode psDom = nodeDom.previousSibling;
                mshtml.IHTMLElement ps = psDom as mshtml.IHTMLElement;
                while (ps != null)
                {
                    if (ps.tagName == node.tagName)
                    {
                        rank++;
                    }
                    psDom = psDom.previousSibling;
                    ps = psDom as mshtml.IHTMLElement;
                }
                if (rank > 1)
                {
                    nodeExpr += "[" + rank + "]";
                }
                else
                { // First node of its kind at this level. Are there any others?
                    mshtml.IHTMLDOMNode nsDom = nodeDom.nextSibling;
                    mshtml.IHTMLElement ns = nsDom as mshtml.IHTMLElement;
                    while (ns != null)
                    {
                        if (ns.tagName == node.tagName)
                        { // Yes, mark it as being the first one
                            nodeExpr += "[1]";
                            break;
                        }
                        nsDom = nsDom.nextSibling;
                        ns = nsDom as mshtml.IHTMLElement;
                    }
                }
                return nodeExpr;
            }
        }
    }