【问题标题】:How to find XML nodes when there is a xmlns=有 xmlns= 时如何查找 XML 节点
【发布时间】:2016-11-21 11:15:48
【问题描述】:

Visual Studio 在运行测试时会创建“.trx”文件,而我正在尝试处理这些文件中的 XML。但是,当我尝试使用 Xpath 表达式访问部分 XML 时,我得到了意想不到的结果。

下面的代码包含一个“.trx”文件的精简版。这些文件包含一个 xmlns="..." 属性,该属性似乎阻止了 Xpath 访问。当xmlns... 被删除时,访问工作并找到预期的节点。

如何更改名称空间管理器 (manager) 或代码(或其他)中的 Xpath,以便在未修改的 XML 中获取与各种 Xpath 匹配的节点列表。

我尝试在 Xpaths 中添加 manager.AddNamespace("ns", trxContent.NamespaceURI); 并包含 ns:,但没有成功。

using System;
using System.Xml;

namespace XpathXmlns
{
    class XpathXmlns
    {
        static string WithXmlns = @"<?xml version=""1.0"" encoding=""UTF-8""?>
<TestRun id=""111"" name=""someName"" runUser=""someUser"" xmlns=""http://microsoft.com/schemas/VisualStudio/TeamTest/2010""> tr1
  <TestSettings name=""Local1"" id=""222"" idx=""333""> ts2
    <Description>Description 1 context.</Description> ts3
  </TestSettings> tr4
  <TestSettings name=""Local2"" id=""333"" idx=""444""> ts5
    <Description>Description 2 context.</Description> ts6
  </TestSettings> tr7
</TestRun>
";

        static void Main(string[] args)
        {
            string WithoutXmlns = WithXmlns.Replace(@" xmlns=""http://microsoft.com/schemas/VisualStudio/TeamTest/2010""", "");

            ProcessXml("WithXmnns", WithXmlns);
            ProcessXml("WithoutXmlns", WithoutXmlns);
        }

        static int counter = 0;
        static XmlNamespaceManager manager;

        static void ProcessXml(string label, string xml)
        {
            Console.WriteLine(label);
            Console.WriteLine(xml);
            XmlDocument trxContent = new XmlDocument();
            trxContent.LoadXml(xml);

            XmlNameTable xmlnt = trxContent.NameTable;
            manager = new XmlNamespaceManager(xmlnt);
            //manager.AddNamespace("ns", trxContent.NamespaceURI);

            XmlNode root = trxContent.DocumentElement;

            Extract(trxContent, "//TestRun");
            Extract(trxContent, "//TestRun/TestSettings");
            Extract(trxContent, "//TestRun/TestSettings/Description");
            Extract(trxContent, "//Description");
            Extract(trxContent, "//TestSettings/@id");
            //Extract(trxContent, "//@id"); // This works OK, it finds the nodes in both cases.
            //Extract(trxContent, "//@idx"); // This works OK, it finds the nodes in both cases.
            Extract(trxContent, "//ns:TestRun");
            Extract(trxContent, "//ns:TestRun/TestSettings");
            Extract(trxContent, "//ns:TestRun/TestSettings/Description");
            Extract(trxContent, "//ns:Description");
            Extract(trxContent, "//ns:TestSettings/@id");
        }

        static void Extract(XmlDocument doc, string xpath)
        {
            counter = 0;
            ExtractNodes("doc-node", doc, xpath);
            ExtractDocNodes("doc", doc, xpath);
            Console.WriteLine();
        }

        private static void ExtractNodes(string source, XmlNode root, string xpath)
        {
            counter++;
            XmlNodeList nodes = root.SelectNodes(xpath, manager);
            ListFoundNodes(source, xpath, nodes);
        }
        private static void ExtractDocNodes(string source, XmlDocument root, string xpath)
        {
            counter++;
            XmlNodeList nodes = root.SelectNodes(xpath, manager);
            ListFoundNodes(source, xpath, nodes);
        }

        private static void ListFoundNodes(string source, string xpath, XmlNodeList nodes)
        {
            Console.WriteLine("    {0,2}: Get {1} from {2} {3}", counter, nodes.Count, source, xpath);
            foreach (XmlNode node in nodes)
            {
                Console.WriteLine("             Nodes  name='{0}'", node.Name ?? "__None__");
            }
        }
    }
}

【问题讨论】:

  • 您使用 XmlDocument 而不是(更简单、更新和 LINQ 友好的)XDocument 有什么原因吗?
  • 搜索“XPath 默认命名空间”并找到该问题的另外 1000 个答案。
  • @spender 谢谢你的建议XDocument,我会看的。我使用了XmlDocument,因为这是我在微软页面上找到的方法。
  • @MichaelKay 关于这个话题有很多问答。我已经查看了您建议的搜索词找到的几个。他们似乎与我的问题不同。也许它们是相同的,但这些问答的措辞方式与我对问题的理解不符。
  • 这里有一个非常相似的:stackoverflow.com/questions/585812/… 如果你不认为它是相同的,那可能是因为你没有掌握术语,在这种情况下,做更多的事情会有所帮助背景阅读。

标签: c# xml xpath


【解决方案1】:

Xmlns 属性定义元素的 xml 命名空间。因此,您的TestRun 元素(以及它下的所有元素)属于命名空间http://microsoft.com/schemas/VisualStudio/TeamTest/2010。所以首先你必须将该命名空间添加到管理器:

XmlNameTable xmlnt = trxContent.NameTable;
manager = new XmlNamespaceManager(xmlnt);
manager.AddNamespace("ns", @"http://microsoft.com/schemas/VisualStudio/TeamTest/2010");

如果不想硬编码,可以使用根元素的命名空间:

XmlNode root = trxContent.DocumentElement;
XmlNameTable xmlnt = trxContent.NameTable;
manager = new XmlNamespaceManager(xmlnt);
manager.AddNamespace("ns", root.NamespaceURI);

然后您必须使用您在查询中定义的命名空间前缀 (ns):

Extract(trxContent, "//ns:TestRun");
// note that all subelements (like TestSettings) are also prefixed
Extract(trxContent, "//ns:TestRun/ns:TestSettings");
Extract(trxContent, "//ns:TestRun/ns:TestSettings/ns:Description");
Extract(trxContent, "//ns:Description");
Extract(trxContent, "//ns:TestSettings/@id");

【讨论】:

  • 经过我的大量实验后,我写了这个问题,现在您在短短几分钟内就提供了解决方案。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-17
  • 1970-01-01
  • 1970-01-01
  • 2011-01-13
  • 1970-01-01
  • 2018-09-09
  • 2023-03-09
相关资源
最近更新 更多