While parsing xml by linq to xml, I came across a strange behaviour (atleast to me). Below is the first xml I parsed
`<?xml version="1.0" encoding="UTF-8"?>
<TestRun>
<UnitTestResult testName = "Arun" outcome = "i">
</UnitTestResult>
<UnitTestResult testName = "Arun1" outcome = "i">
</UnitTestResult>
</TestRun>`
My Code looks like
XDocument doc = XDocument.Parse(fileContents);
var result = doc.Descendants("UnitTestResult");
The above works fine. But If my root node contain attributes the same code is not working. What could be the reason. XML sample below
<?xml version="1.0" encoding="UTF-8"?>
<TestRun id="7903b4ff-8706-4379-b9e8-567034b70abb" name="inaambika#INBELW013312A 2016-02-26 16:55:14" runUser="STC\inaambika" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
<UnitTestResult testName = "Arun" outcome = "i">
</UnitTestResult>
<UnitTestResult testName = "Arun1" outcome = "i">
</UnitTestResult>
</TestRun>
XDocument doc = XDocument.Parse(fileContents);
var result = doc.Descendants("UnitTestResult");
This one below is not ordinary attribute, it is default namespace declaration :
xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010"
Having default namespace declared at the root element level, the root element and all descendant elements without prefix (in this case it means all elements in the posted XML) are in that namespace.
You can use XNamespace + element-local-name to reference element in namespace :
XDocument doc = XDocument.Parse(fileContents);
XNamespace d = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010"
var result = doc.Descendants(d+"UnitTestResult");
Related
How can I read the content of the childnotes using Xpath?
I have already tried this:
var xml = new XmlDocument();
xml.Load("server-status.xml");
var ns = new XmlNamespaceManager(xml.NameTable);
ns.AddNamespace("ns", "namespace");
var node = xml.SelectSingleNode("descendant::ns:server[ns:ip-address]", ns)
Console.WriteLine(node.InnerXml)
But I only get a string like this:
<ip-address>127.0.0.50</ip-address><name>Server 1</name><group>DATA</group>
How can I get the values individually?
Xml file:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<server-status xmlns="namespace">
<server>
<ip-address>127.0.0.50</ip-address>
<name>Server 1</name>
<group>DATA</group>
</server>
</server-status>
You're using XML namespaces in XPath correctly.
However, your original XPath,
descendant::ns:server[ns:ip-address]
says to select all ns:server elements with ns:ip-address children.
If you wish to select the ns:ip-address children themselves, instead use
descendant::ns:server/ns:ip-address
Similarly, you could select ns:name or ns:group elements.
I have this XML
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Header>
<wss:Security xmlns:wss="http://schemas.xmlsoap.org/ws/2002/12/secext">
<wss:UsernameToken>
<wss:Username>username</wss:Username>
<wss:Password>password</wss:Password>
<wss:Nonce></wss:Nonce>
<wss:Created></wss:Created>
</wss:UsernameToken>
</wss:Security>
</S:Header>
<S:Body>
<TaxRegistrationNumber>213213123</TaxRegistrationNumber>
<CompanyName>sadsadasd</CompanyName>
</S:Body>
</S:Envelope>
I want to accesses to the value of <wss:Username> and set a value in <wss:Nonce> node.
I already try 3 ways to get value of <wss:Username> on C# project:
First:
XDocument xmlFile = XDocument.Load(xmlpathfile);
XmlNamespaceManager ns = new XmlNamespaceManager(new NameTable());
ns.AddNamespace("wss", "http://schemas.xmlsoap.org/ws/2002/12/secext/");
XElement UserFinanc = xmlFile.XPathSelectElement("wss:Security/wss:UsernameToken/wss:Username", ns);
Second:
XDocument xmlFile = XDocument.Load(xmlpathfile);
XmlNamespaceManager ns = new XmlNamespaceManager(new NameTable());
var element = xmlFile.Descendants(wss + "Security").Descendants(wss + "UsernameToken").Where(x => x.Descendants(wss + "Username").Any(y => y.Value != "")).First().Element(wss + "UsernameToken");
if (element != null)
MessageBox.Show(element.Element(wss + "Username").Value).Value);
Third:
string grandChild = (string) (from el in xmlFile.Descendants(wss + "Username") select el).First();
MsgBox.Show(grandChild);
I always have similar errors like 'The sequence contains no elements'
Your first attempt is almost right. There are a couple things missing:
The namespace defined in code must be an exact match to the one in the xml. In your case the namespace in code has an extra trailing slash. It should be http://schemas.xmlsoap.org/ws/2002/12/secext.
The XPath expression should be //wss:Security/wss:UsernameToken/wss:Username. The leading slashes basically mean "look for this node anywhere". Alternatively, you could write out the whole path begining with <S:Envelope>. You would need to add the soap envelope namespace to your code as well.
I am trying to get Absoluteentry tag's value from the below xml string, but its displaying objectrefrence not set exception
<?xml version="1.0" ?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
<env:Body>
<AddResponse xmlns="http://www.sap.com/SBO/DIS">
<PickListParams>
<Absoluteentry>120072</Absoluteentry>
</PickListParams>
</AddResponse>
</env:Body>
</env:Envelope>
Code
XDocument doc = XDocument.Parse(xmlstring);
doc.Element("Envelope").Element("Body").Element("AddResponse").Element("PickListParams").Element("Absoluteentry").Value;
Look at the XML:
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
...
That's the Envelope element in the namespace with URI "http://www.w3.org/2003/05/soap-envelope".
Now look at your code:
doc.Element("Envelope")...
That's looking for an Envelope element that's not in any namespace. You should specify the namespace - and the namespaces of the other elements you're looking for:
XNamespace env = "http://www.w3.org/2003/05/soap-envelope";
XNamespace responseNs = "http://www.sap.com/SBO/DIS";
XDocument doc = XDocument.Parse(xmlstring);
var result = doc.Element(env + "Envelope")
.Element(env + "Body")
.Element(responseNs + "AddResponse")
.Element(responseNs + "PickListParams")
.Element(responseNs + "Absoluteentry").Value;
You can use Descendants too. Descendants finds children at any level.
var result = doc.Element(env + "Envelope")
.Element(env + "Body")
.Descendants(responseNs + "Absoluteentry").Value;
<?xml version="1.0" encoding="UTF-8"?>
<Root xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Element xsi:Attribute="Test"></Element>
</Root>
I'm trying to read the "xsi:Attribute" attribute; the code is like this:
var doc = XDocument.Load(new StringReader(xmlText));
var node = doc.Root.Descendants().First();
XNamespace myNamespace = "xsi";
var attribute = node.Attributes(myNamespace + "Attribute").First();
It throws a "Sequence contains no elements" exception in the last line. What am I doing wrong?
You need to use the actual namespace, not "xsi", which is just a local lookup within the XML file itself for the real namespace:
XNamespace myNamespace = "http://www.w3.org/2001/XMLSchema-instance";
Try this (I believe its more generic):
XNamespace myNamespace = doc.Root.GetNamespaceOfPrefix("xsi");
I have an xml file whose structure goes as under(partial)
<?xml version="1.0" encoding="UTF-8"?>
<TestRun id="ee3838c9-a7e2-4ddf-acb1-58589e39422d" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
<TestSettings name="LocalSettings" id="e445106a-c672-4959-94d3-ec8cef9ac7e4">
<Results>
<UnitTestResult executionId="0e790a10-105f-44b1-a8f7-f72709651c17" testId="ae349466-4276-cfa9-908c-026a8589473b" testName="ValidateEmailAddressAndCompanyCode7" computerName="ACCUREVDEV" duration="00:00:41.4297842" startTime="2013-02-27T23:18:52.0238567-08:00" endTime="2013-02-27T23:19:34.0057439-08:00" testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b" outcome="Passed" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" relativeResultsDirectory="0e790a10-105f-44b1-a8f7-f72709651c17">
</UnitTestResult>
<UnitTestResult executionId="e9e7679d-fc39-43b7-a096-819f054a3795" testId="1a808be5-21a5-37c4-5892-2969707ae42f" testName="AccountExtensionSubscriptionWithOneMachineAndThreeSubscriptionsTest_withExpiredMachines" computerName="ACCUREVDEV" duration="00:00:56.1243356" startTime="2013-02-27T23:19:34.0174655-08:00" endTime="2013-02-27T23:20:30.8418287-08:00" testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b" outcome="Passed" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d" relativeResultsDirectory="e9e7679d-fc39-43b7-a096-819f054a3795">
</UnitTestResult> .............................
...............................
As can be make out that, there is a namespace involved
xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010"
Now if I do
string source = #"D:\23_18_43.trx";
XDocument xDoc = XDocument.Load(source);
var xxxx = (from data in xDoc.Descendants("Results")
select data).Descendants("UnitTestResult").ToList();
There is no value coming.
Whereas , if I omit the namespace and do my processing, it works.
How can I proceed without removing the namespace explicitly from the source file? Can it be done programatically?
Thanks
To find a node in XML with a default namespace, you need to still search for that node using the namespace.
Eg.
XNamespace defaultNs = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010";
and then in your "query";
var xxxx = (from data in xDoc.Descendants(defaultNs + "Results")
select data).Descendants(defaultNs +"UnitTestResult").ToList();