【问题标题】:How to use xPath in Selenium WebDriver to grab SVG elements?如何在 Selenium WebDriver 中使用 xPath 来抓取 SVG 元素?
【发布时间】:2015-10-09 19:41:22
【问题描述】:

我正在使用 Selenium WebDriver(Java 版本)测试基于 OpenLayers 的 API。

我想测试一个使用OpenLayers.Control.ModifyFeature 的功能。我想单击绘制的特征 (SVG),然后拖动并检查它们是否存在、可见或隐藏。

我画了一个多边形,我已经选择了它。见下图:

这些 SVG 元素的 HTML 在这里:

<svg id="OpenLayers_Layer_Vector_161_svgRoot" width="1235" height="495" viewBox="0 0 1235 495" style="display: block;">
    <g id="OpenLayers_Layer_Vector_161_root" transform="" style="visibility: visible;">
        <g id="OpenLayers_Layer_Vector_161_vroot">
            <path id="OpenLayers_Geometry_Polygon_200" d=" M 393.0000000000964,213.9999999999891 486.0000000003338,275.9999999997126 384.00000000036925,284.9999999994434 393.0000000000964,213.9999999999891 z" fill-rule="evenodd" fill="blue" fill-opacity="0.4" stroke="blue" stroke-opacity="1" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="none" pointer-events="visiblePainted" cursor="pointer" />
            <circle id="OpenLayers_Geometry_Point_619" cx="439.50000000021464" cy="244.99999999985084" r="6" fill="#009900" fill-opacity="0.5" stroke="#ee9900" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="none" pointer-events="visiblePainted" cursor="inherit" />
            <circle id="OpenLayers_Geometry_Point_621" cx="435.00000000035106" cy="280.49999999958163" r="6" fill="#009900" fill-opacity="0.5" stroke="#ee9900" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="none" pointer-events="visiblePainted" cursor="inherit" />
            <circle id="OpenLayers_Geometry_Point_623" cx="388.50000000023283" cy="249.4999999997126" r="6" fill="#009900" fill-opacity="0.5" stroke="#ee9900" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="none" pointer-events="visiblePainted" cursor="inherit" />
            <circle id="OpenLayers_Geometry_Point_202" cx="393.0000000000964" cy="213.9999999999891" r="6" fill="#990000" fill-opacity="1" stroke="#ee9900" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="none" pointer-events="visiblePainted" cursor="inherit" />
            <circle id="OpenLayers_Geometry_Point_203" cx="486.0000000003338" cy="275.9999999997126" r="6" fill="#990000" fill-opacity="1" stroke="#ee9900" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="none" pointer-events="visiblePainted" cursor="inherit" />
            <circle id="OpenLayers_Geometry_Point_204" cx="384.00000000036925" cy="284.9999999994434" r="6" fill="#990000" fill-opacity="1" stroke="#ee9900" stroke-opacity="1" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="none" pointer-events="visiblePainted" cursor="inherit" />
        </g>
        <g id="OpenLayers_Layer_Vector_161_troot" />
    </g>
</svg>

假设我想选择红点。

我试过了:

String xpath = "//circle[contains(@id, 'OpenLayers_Geometry_Point') AND fill = '#990000']";
List<WebElement> vertices = driver.findElements(By.xpath(xpath));

但它总是返回一个空列表[]

我在这里做错了什么?有人可以帮帮我吗?

非常感谢。

编辑 1 - 函数:verticesAreVisible

在单击操作之前,我想获取元素并检查它们是否可见。我正在使用这个功能。

public static boolean verticesAreVisible(WebDriver driver, String xpath) {
    List<WebElement> list = driver.findElements(By.xpath(xpath));
    if (list.isEmpty()) {
        return false;
    }
    boolean visible = true;
    for (int i = 0; i < list.size(); i++) {
        visible = visible && list.get(i).isDisplayed();
    }
    return !verticesAreNotVisible(driver) && visible;
}

编辑 2 - 正确的 xPath

// This solution from Razib is valid if the SVG is on the root node
String xpath = "/*[name()='svg']/*[name()='circle']";
// I changed it so that any descendant is valid "//"
String xpath = "//*[name()='svg']//*[name()='circle']";
// Since I wanted only the red vertices, I added this
String xpath = "//*[name()='svg']//*[name()='circle' and @fill='#990000']";

【问题讨论】:

  • 您好,我发现这个 xpath 更易于使用,不需要任何操作。 //*[local-name()='svg']//*[local-name()='g' and and @fill='#990000'']

标签: java selenium svg xpath css-selectors


【解决方案1】:

要定位红点,即具有属性 fill="#990000"id 属性包含 OpenLayers_Geometry_Point 的元素,您可以使用以下任一 Locator Strategies

  • 使用

    //*[name()='svg']/*[name()='g']/*[name()='g']//*[name()='circle' and contains(@fill, '990000')][starts-with(@id, 'OpenLayers_Geometry_Point')]
    
  • 使用

    svg > g > g circle[fill$='990000'][id^='OpenLayers_Geometry_Point']
    

理想情况下,您需要为visibilityOfAllElementsLocatedBy() 诱导WebDriverWait,并且可以使用以下任一定位器策略

  • 使用cssSelector

    List<WebElement> vertices = new WebDriverWait(driver, 20).until(ExpectedConditions.visibilityOfAllElementsLocatedBy(By.cssSelector("svg > g > g circle[fill$='990000'][id^='OpenLayers_Geometry_Point']")));
    
  • 使用xpath

    List<WebElement> vertices = new WebDriverWait(driver, 20).until(ExpectedConditions.visibilityOfAllElementsLocatedBy(By.xpath("//*[name()='svg']/*[name()='g']/*[name()='g']//*[name()='circle' and contains(@fill, '990000')][starts-with(@id, 'OpenLayers_Geometry_Point')]")));
    

参考

您可以在以下位置找到一些相关的详细讨论:

【讨论】:

    【解决方案2】:

    尝试了各种技术潜入旅馆,但最后我找到了一种简单的方法来处理这种情况。 当您想要的 svg 没有名称并且适当的 xpath 动态更改时,我使用了“cssSelector”

    WebElement DesiredSvg = driver.findElement(By.cssSelector("#scrollable-auto-tabpanel-0 > div > div > form > div:nth-child(1) > div:nth-child(1) > div > div > div.jss10127 > div > div.jss11602 > svg:nth-child(3)"));
    
    DesiredSvg.click();
    

    【讨论】:

      【解决方案3】:

      在我们实现 SVG 的屏幕之一中,我们也遇到了类似的问题,我使用动作类解决了。

      Action Class Package :
      java.lang.Object
      org.openqa.selenium.interactions.Actions
      

      示例代码:

      WebElement svgObject= driver.findElement(By.xpath(XPATH));
      Actions actionBuilderObj = new Actions(driver);
      actionBuilderObj .click(svgObject).build().perform();
      

      【讨论】:

        【解决方案4】:

        要获得可以使用的可见元素:

        wait = new WebDriverWait(driver, 5);
        wait.until(ExpectedConditions.visibilityOfAllElementsLocatedBy(By.xpath("bla bla")));
        

        【讨论】:

          【解决方案5】:

          您可能需要在Xpath 中使用带有name 属性的操作。 在你的 XPath 中使用它 -

          "/*[name()='svg']/*[name()='SVG OBJECT']"  
          

          然后试试下面的代码sn -p -

          WebElement svgObj = driver.findElement(By.xpath(XPATH));
          Actions actionBuilder = new Actions(driver);
          actionBuilder.click(svgObj).build().perform();
          

          【讨论】:

          • 嗨@Razib。我花了一些时间才让这个工作,但多亏了你的提示,它现在可以工作了! :) 非常感谢!!!有关解决方案的更多详细信息,请参阅我的帖子中的编辑。
          【解决方案6】:

          尝试用@fill 代替fillOpenLayers_Geometry_Point 代替OpenLayers.Geometry.Point

          【讨论】:

          • 嗨@peetya。感谢“OpenLayers_Geometry_Point”提示。我完全忘记用下划线替换点。无论如何,“@fill”提示不起作用。如果我使用这个 xPath '//*[contains(@id, 'OpenLayers_Geometry_Point')]',我会得到 6 分。但我只想要 3 红色。
          猜你喜欢
          • 2013-01-13
          • 2017-06-09
          • 2023-01-25
          • 2020-12-22
          • 1970-01-01
          • 2021-07-22
          • 2021-03-31
          • 1970-01-01
          相关资源
          最近更新 更多