简体   繁体   English

等价于Internet Explorer中Firebug的“复制XPath”吗?

[英]Equivalent of Firebug's “Copy XPath” in Internet Explorer?

I have an Internet Explorer only web application. 我有一个仅Internet Explorer的Web应用程序。

I'm exploring what we can do to automate the testing. 我正在探索如何使测试自动化。

Selenium looks like a good tool, but to be able to activate links etc. I need to tell it where they are. Selenium看起来是一个很好的工具,但是要能够激活链接等,我需要告诉它它们在哪里。 The application wasn't built with this kind of testing in mind, so there generally aren't id attributes on the key elements. 应用程序的构建并不是考虑到这种测试的,因此通常在关键元素上没有id属性。

No problem, I think, I can use XPath expressions. 我认为没问题,我可以使用XPath表达式。 But finding the correct XPath for, say, a button, is a royal pain if done by inspecting the source of the page. 但是,如果要通过检查页面源代码来找到正确的XPath(例如某个按钮),将是一件很痛苦的事情。

With Firefox / Firebug, I can select the element then use "Copy XPath" to get the expression. 使用Firefox / Firebug,我可以选择元素,然后使用“复制XPath”获取表达式。

I have the IE Developer Toolbar and it's frustratingly close. 我有IE开发人员工具栏,它非常令人沮丧。 I can click to select the element of interest and display all sorts of information about it. 我可以单击以选择感兴趣的元素,并显示有关它的各种信息。 but I can't see any convenient way of determining the XPath for it. 但我找不到确定它的XPath的任何便捷方法。

So is there any way of doing this with IE? 那么,使用IE可以做到这一点吗?

I would use bookmarklets. 我会用小书签。 I have one XPath related, but I don't know if it works in IE. 我有一个与XPath相关的文件,但我不知道它是否可以在IE中使用。 I gotta go but I will test it and give it if it works on IE. 我得走了,但是如果它在IE上可以工作,我会对其进行测试并给出。

Two bookmarklet sites for Web developers from my bookmarks: Subsimple's bookmarklets and Squarefree's Bookmarklets . Web开发人员从我的书签中获得的两个小书签站点: Subsimple的小书签Squarefree的小书签 Lot of useful things there... 那里有很多有用的东西...

[EDIT] OK, I am back. [编辑]好,我回来了。 The bookmarklet I had was for FF only, and wasn't optimal. 我拥有的书签仅用于FF,不是最佳选择。 I finally rewrote it, although using ideas from the original one. 我终于重写了它,尽管使用了最初的想法。 Can't find back where I found it. 无法找到我找到它的地方。

Expanded JS: 扩展的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.

You have to select the element and activate the bookmarklet to get its XPath. 您必须选择元素并激活小书签以获取其XPath。

Now, the bookmarklet versions (thanks to Bookmarklet Builder ): 现在,小书签版本(感谢Bookmarklet Builder ):

IE IE浏览器
(I had to break it in two parts, because IE doesn't like very long bookmarklets (max size varies depending on IE versions!). You have to activate the first one (function def) then the second one. Tested with IE6.) (我不得不将其分为两部分,因为IE不喜欢很长的书签(最大大小取决于IE版本!)。您必须先激活第一个(功能def),然后激活第二个(已通过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 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();

Since bookmarklet use puzzled Paul, I though I should add a little introduction to their usage. 由于小书签的使用使Paul感到困惑,因此我应该对其用法进行一些介绍。 I do it in a separate message to avoid mixing stuff. 我在单独的消息中这样做是为了避免混淆。

Bookmarklets (also called favlets) are little JavaScript scripts (sic) designed to be pasted in the address bar of the browser (like any other URL) and thus to run on the current page. 书签(也称为收藏夹)是一些JavaScript小脚本(原文如此),旨在将其粘贴到浏览器的地址栏中(与其他任何URL一样),从而可以在当前页面上运行。
After running it (paste, hit Enter), you can bookmark it for reuse (add it to favorites in IE). 运行它(粘贴,按Enter键)后,您可以将其添加为书签以重用(将其添加到IE中的收藏夹中)。 Note that the browser might bookmark the original URL instead, you have then to edit the bookmark and replace the URL with your script. 请注意,浏览器可能会将原始URL标记为书签,然后您必须编辑书签并将URL替换为脚本。
Of course, you can add it to the URL bar for quick access too. 当然,您也可以将其添加到URL栏中以便快速访问。

These scripts act like being part of the current page, accessing global JS variables and functions, Dom objects, etc. 这些脚本的行为就像是当前页面的一部分,访问全局JS变量和函数,Dom对象等。
They can be super simple, like the seminal javascript: alert("Hello world!"); 它们可以非常简单,就像开创性的javascript: alert("Hello world!"); or quite complex like the one above. 或像上面的那样非常复杂。 If it returns a value (or if last expression has a value), the value replaces the current page. 如果返回值(或者最后一个表达式具有值),则该值将替换当前页面。 To avoid this, you can finish the script with alert (to display a result) or wrap the script in a function definition and call this function, like I did above. 为避免这种情况,您可以像上面我一样,以alert结束脚本(以显示结果)或将脚本包装在函数定义中并调用此函数。 (Some also put void(0); at the end, but I saw it is seen as bad practice.) (有些人最后还把void(0);放到了最后,但是我看到这被认为是不好的做法。)

The function solution has the advantage of making all variables of the script local to the applet (if declared with var , of course), avoiding interferences/side-effects with scripts on the local page. 函数解决方案的优点是使脚本的所有变量都位于applet本地(当然,如果使用var声明),避免了本地页面上的脚本的干扰/副作用。 That's also why the wrapping function should have a name unlikely to clash with a local script. 这就是为什么包装函数应具有不太可能与本地脚本冲突的名称的原因。

Note that some browsers (read: "IE") can limit the size of favlets, the max. 请注意,某些浏览器(阅读:“ IE”)可能会限制收藏夹的大小,即最大 length varying with version (tending to decrease). 长度随版本而变化(趋于减少)。 That's why all useless whitespace is removed (the bookmarlet builder linked above is good for that) and I removed the explict comparisons with null and undefined I usually do. 这就是为什么删除所有无用的空格的原因(上面链接的小册子生成器对此非常有用),并且我删除了通常使用null和undefined进行的显式比较。 I had also to split the favlet in two, first part defining a function (living as long as the page isn't changed/refreshed), second part using it. 我还必须将favlet分为两部分,第一部分定义一个函数(只要不更改/刷新页面就可以使用),第二部分使用它。

Useful tool, particularly on browsers not allowing user scripts (à la Greasemonkey) or without this extension. 有用的工具,特别是在不允许用户脚本(例如Greasemonkey)或没有此扩展名的浏览器上。

I have rewritten the bookmarklet code into C#, so if you'll find it useful, use it ;-) 我已将小书签代码重写为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;
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM