Visual Studio creates ".trx" files when it runs tests and I am trying to process the XML in these files. However I am getting unexpected results when trying to access parts of the XML with Xpath expressions.
The code below includes a cut down version of a ".trx" file. The files contain an xmlns="..."
attribute that appears to prevent the Xpath accesses. The accesses work and find the expected nodes when the xmlns...
is removed.
How do I change the name space manager (manager
) or the Xpaths in the code (or something else) so that I can get the list of nodes matching various Xpaths in the unmodified XML.
I have tried adding manager.AddNamespace("ns", trxContent.NamespaceURI);
and including ns:
in the Xpaths, but without success.
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__");
}
}
}
}