【问题标题】:How to extract XML data using XPath with Selenium Webdriver如何使用 XPath 和 Selenium Webdriver 提取 XML 数据
【发布时间】:2013-10-01 18:19:25
【问题描述】:

我正在使用 Selenium Webdriver (ver 2.31.2.0) (.Net),我正在尝试提取从 `driver.PageSource' 返回的元素 (XML)。

我的问题:如何使用以下 xpath 获取项目列表。 我可以使用 XPATH 插件在 FF 中播放,但相同的代码在 Selenium Webdriver 中不起作用

有什么帮助吗?

这是我在 Selenium Webdriver 中的代码:

var driver = new FirefoxDriver();
driver.Navigate().GoToUrl("http://website_name/languages.xml");
string _page_source = driver.PageSource;
ReadOnlyCollection<IWebElement> webElements = _page_source.FindElementsByXPath("//response//results//items/vList");

我的 xml 看起来像这样:

<response xmlns="http://schemas.datacontract.org/2004/07/myproj.cnn.com">
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <meta>

    </meta>
    <results i:type="vList">
        <name>Language</name>
        <queryValue>language</queryValue>
        <displayOrder>0</displayOrder>
        <items>
            <vList>
                <name>English</name>
                <displayName>English</displayName>
                <displayOrder>0</displayOrder>
                <items />
            </vList>
            <vList>
                <name>Swedish</name>
                <displayName>Swedish</displayName>
                <displayOrder>1</displayOrder>
                <items />
            </vList>
        </items>
    </results>
</response>

【问题讨论】:

  • 你想要的价值观是什么?
  • 所以我将查找vListdisplayName 的总数

标签: xpath selenium selenium-webdriver


【解决方案1】:

您可以使用 selenium 浏览并获取 xml,但使用 .net 类处理 xml。

driver.PageSource 属性是一个字符串,您应该直接使用 .Net 类来解析表示的 xml。此外,字符串对象上没有方法FindElementsByXPath(),除非这是您编写的扩展方法。

使用 selenium 中的driver.PageSource 读取 xml

var driver = new FirefoxDriver();
driver.Navigate().GoToUrl("http://website_name/languages.xml");
XmlReader reader = XmlReader.Create(driver.PageSource);

或者,通过使用直接浏览到 url 来读取 xml

XmlReader reader = XmlReader.Create("http://website_name/languages.xml");

然后使用下面的代码来解析和读取xml。 需要注意的关键点是命名空间信息是如何提供给 xpath 的。

//load xml document
XElement xmlDocumentRoot = XElement.Load(reader);
//also add the namespace infn, chose a prefix for the default namespace
XmlNameTable nameTable = reader.NameTable;
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(nameTable);
namespaceManager.AddNamespace("a", "http://schemas.datacontract.org/2004/07/myproj.cnn.com");

//now query with your xml - remeber to prefix the default namespace
var items = xmlDocumentRoot.XPathSelectElements("//a:results/a:items/a:vList", namespaceManager);

Console.WriteLine("vlist has {0} items.", items.Count());

foreach (var item in items)
{
Console.WriteLine("Display name: {0}", item.XPathSelectElement("a:displayName",namespaceManager).Value);
}
// OR get a list of all display names using linq
var displayNames = items.Select(x => x.XPathSelectElement("a:displayName", namespaceManager).Value).ToList();

您将需要以下命名空间才能使上述工作:

using System;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;

【讨论】:

  • 感谢 Faiz:当我尝试执行 string _pageSource = driver.PageSource; XmlReader reader = XmlReader.Create(_pageSource); 时,我收到了 Illegal characters in path
  • 通过将 xml 保存到文件并使用 XmlReader reader = XmlReader.Create(@"D:\test\file.xml"); 进行基本测试。我已经对此进行了测试,并且可以正常工作。虽然,您之前发布的 xml 需要修复 - response 标记在两个命名空间之间错误关闭。
  • 终于完成了我最终添加的仅有的两行,以便使其正常工作using (var strReader = new StringReader(_pageSource)) using (var reader = XmlReader.Create(strReader)) { .......}
【解决方案2】:

您发布的 XML 输入声明了一个命名空间:xmlns="http://schemas.datacontract.org/2004/07/myproj.cnn.com"。见下一行:

<response xmlns="http://schemas.datacontract.org/2004/07/myproj.cnn.com">

因为这个命名空间没有前缀,所以它是所有没有前缀的元素的默认命名空间。这意味着元素&lt;response&gt; 和元素&lt;results&gt; 等都属于这个命名空间。

阅读下一篇:http://www.w3schools.com/xml/xml_namespaces.asp

因此,在您的代码中,您需要先声明命名空间,然后才能进行任何 XPath 评估。我不知道如何在 Selenium Webdriver 中设置命名空间,但我猜你可以找到它。

一旦你声明了命名空间,你就需要在你的 XPath 中使用它。例如,在 XSLT 中,您可以如下声明命名空间:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:foo="http://schemas.datacontract.org/2004/07/myproj.cnn.com">

我现在用前缀foo 声明了命名空间。可用于检索所有 vList 元素的 XPath 是:

/foo:response/foo:results/foo:items/foo:vList

要获取您可以使用的所有 displayName 元素:

/foo:response/foo:results/foo:items/foo:vList/foo:displayName

如果您想要元素的总数而不是元素列表,您可以将count() 包裹起来,如下所示:

count(/foo:response/foo:results/foo:items/foo:vList)
count(/foo:response/foo:results/foo:items/foo:vList/foo:displayName)

您使用的 XPath 中有很多 //。仅在确实需要时才使用//,因为如果您已经知道路径,它将扫描整个文件并占用比必要更多的资源。

【讨论】:

  • 谢谢,我无法控制 xml,也无法向该 xml 添加名称空间,我有哪些选项,我的意思是如果我没有名称空间,那么我不会使用?
  • @AbuHamzah 当然,您无法控制输入 XML。您也不需要向输入 XML 添加名称空间。我是说输入 XML 已经有一个默认命名空间。这个命名空间应该在你的 Selenium 代码中使用,以便能够使用 XPath
猜你喜欢
  • 1970-01-01
  • 2018-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-04
  • 2019-09-04
  • 1970-01-01
相关资源
最近更新 更多