enter code herein the XML document :
<foo>
<bar><para> test </para> </bar>
<bar>text</bar>
<bar>stackoverflow</bar>
</foo>
I am trying to parse it and only get the Strings in bar; by using this way:
[function where node is the foo]
foreach (XmlNode subNode in node.ChildNodes)
{
if (subNode.Name == "bar")
{
if (!String.IsNullOrWhiteSpace(subNode.InnerText))
Debug.WriteLine(subNode.Name + " - " subNode.InnerText);
}
}
However it gives me test
Thanks
This is what you are looking for (EDITTED based on you updated question)
XDocument doc = XDocument.Load(path to your xml file);
XNamespace ns = "http://docbook.org/ns/docbook";
var result = doc.Root.Descendants(ns + "para")
.Where(x => x.FirstNode.NodeType == System.Xml.XmlNodeType.Text)
.Select(x => x.Value)
.ToList();
In your updated xml I see you are using a namespace so the name of your node is not para but it's theNameSpace + "para". The namespace is defined in the first line of your xml file. Also you can see this sample too.
Do you want "test"? Try following :
string input =
"<foo>" +
"<bar><para> test </para> </bar>" +
"<bar>text</bar>" +
"<bar>stackoverflow</bar>" +
"</foo>";
XDocument doc = XDocument.Parse(input);
List<string> bars = doc.Descendants("bar").Where(x => x.NextNode != null).Select(x => (string)((XElement)x.NextNode)).ToList();
Related
I try to parse an xml file with XDocument class, with criteria that if the child node matches a given string, its parent node is selected.
<SalesQuotes xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://api.some.com/version/1">
<Pagination>
<NumberOfItems>2380</NumberOfItems>
<PageSize>200</PageSize>
<PageNumber>1</PageNumber>
<NumberOfPages>12</NumberOfPages>
</Pagination>
<SalesQuote>
<Guid>825634b9-28f5-4aa7-98e7-5e4a4ed6bc6a</Guid>
<LastModifiedOn>2018-01-09T12:23:56.6133445</LastModifiedOn>
<Comments>Please note:
installation is not included in this quote
</Comments>
</SalesQuote>
</SalesQuotes>
I tried using
var contents = File.ReadAllText(path: "test1.xml");
var doc = XDocument.Parse(contents);
var root = doc.Root;
var sq = root.Elements("SalesQuote");//return null
var theQuote = root.Elements("SalesQuote").Where(el => el.Element("Guid").Value == "825634b9-28f5-4aa7-98e7-5e4a4ed6bc6a");//return null
var theAlternativeQuote =
from el in doc.Descendants("SalesQuote").Elements("Guid")
where el.Value == "825634b9-28f5-4aa7-98e7-5e4a4ed6bc6a"
select el;//return null
I can't seem to find what's wrong.
Any help is much appreciated! Thanks.
You ignored the namespace bro.
Do remove the xmlns attribute in your XML or try this:
var contents = File.ReadAllText("XMLFile1.xml");
var doc = XDocument.Parse(contents);
var root = doc.Root;
XNamespace ns = "http://api.some.com/version/1";
var sq = root.Descendants(ns + "SalesQuotes"); //return null
var theQuote = root.Elements(ns + "SalesQuote")
.Where(el => el.Element(ns + "Guid").Value == "825634b9-28f5-4aa7-98e7-5e4a4ed6bc6a"); //return null
var theAlternativeQuote =
from el in doc.Descendants(ns + "SalesQuote").Elements(ns + "Guid")
where el.Value == "825634b9-28f5-4aa7-98e7-5e4a4ed6bc6a"
select el; //return null
If you are not too concerned about keeping your current implementation, you could consider using a Typed DataSet and load your XML into fully typed, structured objects.
Querying those objects with Linq will be more straight forward than what I see in your current implementation.
You might also find this useful:
SO Question: Deserialize XML Document to Objects
yap, you're missing the namespace that you can grab with document.Root.GetDefaultNamespace()
// Load
var document = XDocument.Parse(xml);
var xmlns = document.Root.GetDefaultNamespace();
// Find
var query = from element in document
.Descendants(xmlns + "SalesQuote")
.Elements(xmlns + "Guid")
where element.Value == "825634b9-28f5-4aa7-98e7-5e4a4ed6bc6a"
select element;
I have an XML file with a structure similar to this
<entry name="something">
<members>
<member>aaa</member>
<member>bbb</member>
</members>
</entry>
<entry name="something_else">
<members>
<member>ccc</member>
<member>ddd</member>
</members>
</entry>
I need to be able to get the values out of each of the member nodes to store in a datatable. if i use the innertext property, it concatenates the values (aaabbb). there is nothing discernible to split the string on. I can also use the inner XML but then i just get a string with the XML structure (aaa bbb<\member>)
What is the best way to get each value out of the XML elements and store it in a string array?
here is what I have been trying.
foreach (XmlNode grpNode in GrpList)
{
subNode = grpNode.Attributes["name"];
if (subNode != null)
{
Obj = grpNode.Attributes["name"].Value;
}
subNode = grpNode["members"];
if (subNode != null)
{
string innerXml = string.Empty;
innerXml = grpNode["members"].InnerXml.ToString();
string[] tempArrary = innerXml.Split(new char[] {'>', '<'});
}
}
You can use Xpath to iterate through Entry nodes and get the members within it like this
string xml = "<root><entry name='something'>" +
"<members>" +
"<member>aaa</member>" +
"<member>bbb</member>" +
"</members>" +
"</entry>" +
"<entry name='something_else'>" +
"<members>" +
"<member>ccc</member>" +
"<member>ddd</member>" +
"</members>" +
"</entry></root>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
var memsList = doc.SelectNodes("//entry");
foreach (XmlNode a in memsList)
{
Console.WriteLine(a.Attributes["name"].Value);
var memList = a.SelectNodes("members/member");
foreach(XmlNode x in memList)
Console.WriteLine(x.InnerText);
}
You need to iterate the child elements within members, so something like:
foreach (var node in grpNode["members"].ChildNodes)
{
var value = node.InnerText;
}
That said, you would be better off using LINQ to XML unless you have some specific reason to use XmlDocument. This gives you much more expressive code, for example:
var doc = XDocument.Parse(xml);
var something = doc.Descendants("entry")
.Where(e => (string)e.Attribute("name") == "something")
.Single();
var somethingMembers = something.Descendants("member")
.Select(e => e.Value)
.ToArray();
This should do the trick:
XDocument xdoc = XDocument.Load(#"Path/to/file");
var result = xdoc.Descendants("member").Select (x => x.Value).ToArray();
Result:
Demo Code
the xml you've provided isn't valid. But assuming you just want the inner text of all member nodes into a string array, I'd just use Linq-To-Xml (XDocument):
var results = XDocument.Parse(xmlString)
.Descendants("member")
.Select(m => m.Value)
.ToArray();
Even though you're using the old XmlDocument API, by throwing in an .OfType<XmlNode>() you can convert an XmlNodeList to a generic enumerable and thereby mix in some linq and lambda syntax, for instance:
var tempArrary = subNode.SelectNodes("member").OfType<XmlNode>().Select(n => n.InnerText).ToArray();
I have a xml given below
<session xmlns="http://test.net/schema/session/1.0" name="test" start="2015-07-01T07:20:31.425Z">
<download>
<filename value="/UAT/Incoming/ Status/Archive/8-22-2011 3-20-14 PM306.xml" />
<result success="false">
<message>Timeout waiting .</message>
</result>
</download>
</session>
I want to select the message node value only if Result node value is false.
I donot want to check on hard coded parent node like node download because it may change
Can anyone help me please..
XDocument doc = XDocument.Load("your xml file path");
var result = doc.Elements().
First(e => e.Name == "download")
.Elements().First(e => e.Name == "result");
if (result.Attributes().First(a => a.Name == "success").Value == "false")
return result.Elements().First(e => e.Name == "message").Value;
This worked for me:
XNamespace ns = XNamespace.Get("http://test.net/schema/session/1.0");
IEnumerable<XElement> failures =
doc
.Descendants(ns + "download")
.Concat(doc.Descendants(ns + "upload"))
.Elements(ns + "result")
.Elements(ns + "message")
.Where(e => e.Parent.Attributes("success").Any(a => !(bool)a));
From your input I got this:
First of all you need to set the namespace for your XML file like this:-
XNamespace ns = "http://test.net/schema/session/1.0";
I will start looking into descendants of download because I need to find the result element which contains the success attribute (whose value we want to check). Thus, a simple where condition will filter those nodes for us and finally we can select the message node.
Update:
You can use Concat if you want to search both download & upload like this:-
IEnumerable<XElement> result = xdoc.Descendants(ns + "download")
.Concat(xdoc.Descendants(ns + "upload"))
.Where(x => x.Element(ns + "result") != null &&
(string)x.Element(ns + "result").Attribute("success") == "false")
.Select(x => x.Element(ns +"result").Element(ns +"message"));
I am also checking in the where clause if result node exist or not by checking for null, otherwise it may result in Null reference exception.
Using some XPath, the following piece of code should work
string xml = #"<session xmlns=""http://test.net/schema/session/1.0"" name=""test"" start=""2015-07-01T07:20:31.425Z"">
<download>
<filename value=""/UAT/Incoming/ Status/Archive/8-22-2011 3-20-14 PM306.xml"" />
<result success=""false"">
<message>Timeout waiting .</message>
</result>
</download>
</session>";
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(xml);
// Here, you load the namespace used in your xml. You'll need it later in your XPath queries
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xdoc.NameTable);
nsmgr.AddNamespace("test", "http://test.net/schema/session/1.0");
// XPath to select the "result" node whose attribute "success" equals false
XmlElement xelt = xdoc.DocumentElement.SelectSingleNode("descendant::test:download/test:result[#success=\"false\"]", nsmgr) as XmlElement;
// return the "message" node
return xelt.FirstChild as XmlElement;
As already mentioned, you'll find more details about XPath expression on this link: https://msdn.microsoft.com/en-us/library/d271ytdx%28v=vs.110%29.aspx
I am trying to get the ResponseCode attribute value out of this XML.
The XML is an XDocument
<IDMResponse xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" MajorVersion="1" xmlns="http://www.fake.org/namespace/">
<ARTSHeader>
<Response ResponseCode="Rejected">
<RequestID>1</RequestID>
<BusinessError Severity="Error">
<Code>IdmInvalidUserNamePasswordLoginProvided</Code>
<Description>Invalid username or password, if problem persists, please contact Administrator</Description>
</BusinessError>
</Response>
</ARTSHeader>
</IDMResponse>
With XPath: (No error checks done)
XmlNamespaceManager nsm = new XmlNamespaceManager(new NameTable());
nsm.AddNamespace("def", "http://www.fake.org/namespace/");
XDocument doc = XDocument.Parse(xml);
string code =
doc
.XPathSelectElement(#"/def:IDMResponse/def:ARTSHeader/def:Response", nsm)
.Attribute("ResponseCode")
.Value;
foreach (XElement el in doc.Root.Elements())
{
if(el.Name.ToString() == "ARTSHeader")
foreach(XElement ell in el.Elements())
{
if(ell.Name.ToString() == "Response")
string responseCode = ele.Attribute("ResponseCode").Value;
}
}
Does this work for you? I dont know the whole structure of your xml so you might need to go deeper into the nested xml to get to Response first
One possible way :
.....
XNamespace ns = "http://www.fake.org/namespace/";
string responseCode = (string)doc.Descendants(ns+"Response")
.First()
.Attribute("ResponseCode");
Console.WriteLine(responseCode);
You could try this one out, I haven`t tested so you might need to rearrange some structure
XDocument doc1 = XDocument.Parse(soapResult);
XNamespace ns1 = "http://www.fake.org/namespace/";
var items = doc1.Descendants(ns1 + "ARTSHeader").Descendants(ns1 + "Response").First().Attribute("ResponseCode").Descendants(ns1 + "BusinessError").First().Attribute("Severity")
.Select((x) => new
{
Code = x.Element(ns1 + "Code").Value,
Description = x.Element(ns1 + "Description").Value,
});
I have this XML
<?xml version="1.0" encoding="UTF-8" ?>
<uclassify xmlns="http://api.uclassify.com/1/ResponseSchema" version="1.01">
<status success="true" statusCode="2000"/>
<readCalls>
<classify id="cls1">
<classification textCoverage="1">
<class className="female" p="0.932408"/>
<class className="male" p="0.0675915"/>
</classification>
</classify>
</readCalls>
</uclassify>
or similar. What matters is, I don't have
<tag>value</tag>
but
<tag attribute1 attribute2 ... />.
What I want to output is for instance
attribute1: attributevalue1
So I want to enter a term like "female" and I want it to output 0.932408.
What I tried to get started
string xml = HttpGet("http://uclassify.com/browse/" + username + "/" + classifiername + "/" + operation + "?" + paramz.ToString());
XDocument doc = XDocument.Parse(xml);
var list = doc.Root.Elements("uclassify")
.Select(element => element.Value)
.ToList();
But list is always empty, which is presumably because there are no values, only attributes.
EDIT:
current version
string xml = HttpGet("http://uclassify.com/browse/" + username + "/" + classifiername + "/" + operation + "?" + paramz.ToString());
XDocument doc = XDocument.Parse(xml);
XNamespace ns = "http://api.uclassify.com/1/ResponseSchema";
var list = doc.Root.Descendants(ns + "class")
.Select(element => element.Value)
.ToList();
textBox1.Text = string.Join(",", list.ToArray());
Result is a comma.
SO your problem is the default namespace:
xmlns="http://api.uclassify.com/1/ResponseSchema"
To fix it, you need to qualify your element selector.
You can do this like so...
XNamespace ns = "http://api.uclassify.com/1/ResponseSchema";
var list = doc.Root.Descendants(ns + "class")
.Select(element => element.Value)
.ToList();
I've modified your code slightly to select all the class nodes, but you can see that I've prefaced your "class" in the Descendants() call with the namespace variable ns.
EDIT:
So now your problem is that you are selecting the element's values, not the attributes values...
so if we are building a dictionary of attribute names to attribute values, you might want to use some code like this:
Dictionary<string,double> dictionary = doc.Root.Descendants(ns + "class")
.ToDictionary(
element => element.Attribute("className").Value,
element => double.Parse(element.Attribute("p").Value));
foreach(var item in dictionary)
{
Console.WriteLine(string.Format("{0}: {1}", item.Key, item.Value));
}
so a couple of caveats:
I'm assuming that each of the className attributes in the class attributes are unique, otherwise you'll have an exception
I'm assuming the value of the attribute p is a double.