C# 存在xmlns时如何查找XML节点=

C# 存在xmlns时如何查找XML节点=,c#,xml,xpath,C#,Xml,Xpath,Visual Studio在运行测试时创建“.trx”文件,我正在尝试处理这些文件中的XML。然而,当我尝试使用Xpath表达式访问XML的某些部分时,会得到意想不到的结果 下面的代码包括“.trx”文件的精简版本。这些文件包含一个xmlns=“…”属性,该属性似乎阻止Xpath访问。当删除xmlns…时,访问将工作并找到预期的节点 如何更改名称空间管理器(manager)或代码中的XPath(或其他内容),以便在未修改的XML中获得与各种XPath匹配的节点列表 我已经尝试添加manager.

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

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

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

我已经尝试添加
manager.AddNamespace(“ns”,trxContent.NamespaceURI)
并在XPath中包含
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__");
            }
        }
    }
}
使用系统;
使用System.Xml;
命名空间XpathXmlns
{
类XpathXmlns
{
带xmlns=@的静态字符串
tr1
ts2
说明1上下文.ts3
tr4
ts5
说明2上下文。ts6
tr7
";
静态void Main(字符串[]参数)
{
字符串WithoutXmlns=WithXmlns.Replace(@“xmlns=”)http://microsoft.com/schemas/VisualStudio/TeamTest/2010""", "");
ProcessXml(“WithXmnns”,WithXmlns);
ProcessXml(“WithoutXmlns”,WithoutXmlns);
}
静态整数计数器=0;
静态XmlNamespaceManager;
静态void ProcessXml(字符串标签,字符串xml)
{
控制台写入线(标签);
Console.WriteLine(xml);
XmlDocument trxContent=新的XmlDocument();
LoadXml(xml);
XmlNameTable xmlnt=trxContent.NameTable;
manager=新的XmlNamespaceManager(xmlnt);
//manager.AddNamespace(“ns”,trxContent.NamespaceURI);
XmlNode root=trxContent.DocumentElement;
提取(trxContent,//TestRun);
提取(trxContent,“//TestRun/TestSettings”);
提取(trxContent,“//TestRun/TestSettings/Description”);
摘录(trxContent,//Description);
提取(trxContent,“//TestSettings/@id”);
//Extract(trxContent,“//@id”);//这可以正常工作,它在两种情况下都会找到节点。
//Extract(trxContent,“//@idx”);//这可以正常工作,它在两种情况下都会找到节点。
提取(trxContent,“//ns:TestRun”);
提取(trxContent,“//ns:TestRun/TestSettings”);
提取(trxContent,“//ns:TestRun/TestSettings/Description”);
摘录(trxContent,“//ns:Description”);
提取(trxContent,“//ns:TestSettings/@id”);
}
静态void提取(XmlDocument文档,字符串xpath)
{
计数器=0;
提取节点(“doc节点”、doc、xpath);
ExtractDocNodes(“doc”、doc、xpath);
Console.WriteLine();
}
私有静态节点(字符串源、XmlNode根、字符串xpath)
{
计数器++;
XmlNodeList nodes=root.SelectNodes(xpath,管理器);
ListFoundNodes(源、xpath、节点);
}
私有静态void ExtractDocNodes(字符串源、XmlDocument根、字符串xpath)
{
计数器++;
XmlNodeList nodes=root.SelectNodes(xpath,管理器);
ListFoundNodes(源、xpath、节点);
}
私有静态void ListFoundNodes(字符串源、字符串xpath、XmlNodeList节点)
{
WriteLine({0,2}:从{2}{3}获取{1}),计数器,节点,计数,源,xpath);
foreach(节点中的XmlNode节点)
{
Console.WriteLine(“Nodes name='{0}',node.name???”;
}
}
}
}

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");

您使用XmlDocument而不是(更简单、更新且对LINQ友好的)XDocument有什么原因吗?请搜索“XPath默认名称空间”并找到1000个关于这个问题的答案。@spender感谢您建议
XDocument
,我会看一看。我使用了
XmlDocument
,因为这是我在Microsoft页面上找到的方法。@MichaelKay关于这个话题有很多问答。我已经查看了您建议的搜索词找到的几个。他们似乎与我的问题不同。也许它们是一样的,但这些Q&A的措辞与我对问题的理解不符。这里有一个非常相似的问题:如果你不认为它是相同的,那么可能是因为你没有掌握术语,在我做了大量的实验后,我写了这个问题,现在你在几分钟内就提供了一个解决方案。非常感谢。