I have an XML document that i have deserialized according to my model class, now i want to convert it into an IEnumerable<XmlDocument> or IEnumerable<string> which is the return type of my function so i could return valid XML reply from my MVC REST API.
XmlDocument xml = new XmlDocument();
xml.LoadXml(responseStream);
XmlSerializer x = new XmlSerializer(typeof(mSchoolModel));
mSchoolModel mgp = (mSchoolModel)x.Deserialize(responseObj.GetResponseStream());
//return xml;
So can anyone help me how can i convert this into an IEnumerable?
Use the LINQ-to-XML API.
Convert your XmlDocument instance to an XDocument instance. Instructions available at: http://blogs.msdn.com/b/xmlteam/archive/2009/03/31/converting-from-xmldocument-to-xdocument.aspx
Use the Elements() or Descendants() methods on the XDocument instance to get an IEnumerable<XElement>
Transform the IEnumerable<XElement> to an IEnumerable<string> using the LINQ Enumerable.Select() operator.
Here's a simple example:
IEnumerable<string> elements
= XDocument
.Load(new XmlNodeReader(xml))
.Elements()
.Select(element => element.ToString());
*Note: since a valid XML document can only have one root node, the resulting collection from the example above won't be very interesting, but you should have enough here to get what it is that you need. If you're familiar with XPath, you may find it easier to get the elements you want using the XPath extensions to LINQ to XML. See: How To: Query LINQ to XML Using XPath
Update
Realized I may have read your question wrong. If you have an XmlDocument instance and you need to return an IEnumerable<XmlDocument> all you have to do is wrap the instance in a collection. For example,
IEnumerable<XmlDocument> xmlCollection = new XmlDocument[]{ xml };
Of course, this approach can be used for wrapping any object into a singleton collection of objects of the same type.
Related
I have done the below many times using a xmlDocument approach, but I wanted to use the more powerful linq to xml approach.
However, I seem to have run into a wall.
I am getting data back from a restful API from twillio / crmText.
Here is a link to their site where their docs live:
http://crmtext.com/api/docs
Here is my XML string:
<response op="getcustomerinfo" status="200" message="ok" version="1.0">
<customer>
<totalMsg>3</totalMsg>
<custId>9008281</custId>
<custName></custName>
<timestamp>2015-04-30 16:17:19</timestamp>
<optinStatus>3</optinStatus>
<custMobile>6185551212</custMobile>
<subacct>1st Choice Courier</subacct>
</customer>
</response>
I need to find out the optinStatus. It should return 3.
I am using the below, which return the above xml
XDocument xdoc = XDocument.Parse(result1);
I have tried about 4000 different things, including:
IEnumerable<XElement> otinStatus = from el in xdoc.Elements("customer") select el;
IEnumerable<XElement> otinStatus2 = from el in xdoc.Elements("cusotmer.optinStatus") select el;
IEnumerable<XElement> otinStatus3 = from el in xdoc.Elements("optinStatus") select el;
All of which returns no results.
Please help, I know this is something simple I am missing.
Thank you in advance -- Joe
Retrieve an Element's Value
var status = xDoc
.Descendants("optinStatus") // get the optinStatus element
.Single() // we're expecting a single result
.Value; // get the XElement's value
Example
Here is a working Fiddle for you. You can see it running live here. The output is 3.
using System;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
public class Program
{
public static void Main()
{
var xDoc = XDocument.Parse(xmlString);
var status = xDoc.Descendants("optinStatus").Single();
Console.WriteLine(status.Value);
}
private static string xmlString = #"
<response op=""getcustomerinfo"" status=""200"" message=""ok"" version=""1.0"">
<customer>
<totalMsg>3</totalMsg>
<custId>9008281</custId>
<custName></custName>
<timestamp>2015-04-30 16:17:19</timestamp>
<optinStatus>3</optinStatus>
<custMobile>6185312349</custMobile>
<subacct>1st Choice Courier</subacct>
</customer>
</response>
";
}
Explanation
Descendents() is an instance axes method (or just axes in shorthand). It returns an IEnumerable<XElement> of all matching descendents. On its results, we call Single(). It is a Linq method that returns the only element of a sequence. If there is more than one element, it throws an error. We're left with a single XElement. This represent an entire XML element. Since we only want its value not the entire element, we call the Value property. Bingo, we're done.
A Bit More Detail
Axes come in two kinds:
Instance axes methods, which MSDN lists here, are invokable members of the XElement, XDocument, and XNode classes.
Extension axes methods, which MSDN lists here, are invokable on collections.
With one exception, an axes method returns a collection of type IEnumerable<T>. The exception is Element(), which returns the first matching child object. That what AmatuerDev used and, as in your question, if you are only expecting a single result, it is a just as good if not better approach that is Descendants().
Retrieve an Attribute Value
Once we have an XElement, we can retrieve one of its attributes instead of its value. We do that by calling the Attributes() method. It returns the matching XAttribute. Since we only want the attribute value, we call the Value property. Voila.
// for attribute
var response = xDoc.Descendants("response").Single();
var attr = response.Attribute("status");
General Approach
Using Linq to XML is a two step process.
Call an axes method to obtain an IEnumerable<T> result.
Use Linq to query that.
See Also
Here is some relevant MSDN documentation:
How to: Retrieve the Value of an Element (LINQ to XML)
LINQ to XML Axes
Assuming xDoc being the XDocument. Have you tried..
var customer = xDoc.Root.Element("customer");
var optinStatus = customer.Element("optinStatus");
var optinStatusValue = optinStatus.Value;
I have a Xml document that I want to convert into a XnlNodeList using a linq query. Now, neither Xml nor Linq are something know well. The error I'm getting is Cannot implicitly convert type 'System.Linq.IOrderedEnumerable<System.Xml.XmlElement>' to 'System.Xml.XmlNodeList'. An explicit conversion exists (are you missing a cast?).
XmlNodeList abTestDocx = abTestDoc.GetElementsByTagName("FS").OfType<XmlElement>().OrderBy(FS => FS.GetAttribute("label"));
Thanks!
You don't generally create XmlNodeList instances yourself. Do you really need one though? If you just need to iterate over the nodes, just assign it to an IEnumerable<XmlElement>:
IEnumerable<XmlElement> abTestDocx = abTestDoc
.GetElementsByTagName("FS")
.OfType<XmlElement>()
.OrderBy(fs => fs.GetAttribute("label"));
Note that using LINQ to XML is generally nicer than the old XmlDocument API. Then you'd just need:
IEnumerable<XElement> abTestDocx = doc
.Descendants("FS")
.OrderBy(fs => (string) fs.Attribute("label"));
... and all kinds of other things would be simpler too. LINQ to XML is lovely :)
My application gets data from SharePoint web service (using SOAP and CAML query), I am using a Xdocument doc to store retrieved xmlNode and then assign xdocument to XMLDataSource which is binned to gridView.
Now I need to filter the Xdocument before binding, to pick only those records where an element (ows_Partner_x0020_Type) matches a variable.
I am trying like this :
doc = doc.Descendants(z + "row").Where(rows => rows.Attribute("ows_Partner_x0020_Type").Value == Partner_Type.SelectedValue);
or
var bar = doc.Descendants(z + "row").Where(rows => rows.Attribute("ows_Partner_x0020_Type").Value == Partner_Type.SelectedValue);
but the problem is that return type of above LINQ is System.Collections.Generic.IEnumerable<System.Xml.Linq.XElement>
which is quit nothing like XDocument, which is required format to bind to XMLDataSource as doc.ToString().
Hope I am able to explain the problem.
Thanks a lot in advance.
Vishal
If you're just trying to create a document with those elements, you can use:
XDocument filteredDocument = new XDocument(new XElement("root", bar));
(That will create a document with a root element of <root>, and all the elements you're interested in directly under that.)
Not quite sure about all the binding parts - I strongly suspect there may be a better alternative - but this will certainly give you a new XDocument.
What is best way to search in XML document to retrieve one or more records against search criteria. Suggestions are welcomed.
Personally I'd use LINQ to XML if you possibly can. Your question is very vague at the moment, but for example, you could write:
XDocument doc = XDocument.Load("test.xml");
var matches = doc.Descendants("Person")
.Where(x => (string) x.Attribute("Name") == "Jon")
.Where(x => x.Elements("Child").Count() >= 2);
While you can use XPath, I generally prefer not to - it has all the normal problems of embedding one language within another, whereas using LINQ to XML you're using C# throughout, so you have no new syntax to learn - just the relevant methods within the LINQ to XML library.
LINQ to XML also makes namespace handling simple, and you don't need to worry about escaping values etc, as your query is all in code rather than in a string.
.net xml documents have good support for xpath.
It should work for most of your xml searches.
Take a look at XPath Examples
Use XPath by XmlDocument.SelectNodes or SelectSingleNode like this:
XmlDocument doc = new XmlDocument();
doc.Load("bookstore.xml");
XmlNode root = doc.DocumentElement;
// Add the namespace.
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("bk", "urn:newbooks-schema");
// Select and display the first node in which the author's
// last name is Kingsolver.
XmlNode node = root.SelectSingleNode(
"descendant::bk:book[bk:author/bk:last-name='Kingsolver']", nsmgr);
Console.WriteLine(node.InnerXml);
I know there's no built in converter to convert an array of objects to XML. Is there a quick rudimentary way to create a XML out of the array to help me do a LINQ to XML join between this one and another XML I have?
You can use Linq to XML, it is really easy to map from your existing data structures to XML, i.e.:
int[] values = { 1, 2, 17, 8 };
XDocument doc = new XDocument();
doc.Add(new XElement("root", values.Select( x=> new XElement("item", x))));
produces the following output:
<root>
<item>1</item>
<item>2</item>
<item>17</item>
<item>8</item>
</root>
You can always use XmlSerializer to transform a list of C# objects to XML document. The result of the serialization may be customized by using metadata attributes to designate, for example, root nodes or which class property is to be ignored etc... You will definitely need to apply the attributes to make the resulting XML conform as much as possible to your requirements.
Here is a basic tutorial on serializing an Object to XML: