Read CDATA section based on where clause using LINQ - c#

I am trying to read CDATA section of an xml node based upon the where clause.
<Book>
<BookItem ISBN="SKS84747"><![CDATA[20]]> </BookItem>
<BookItem ISBN="LHKGOI84747"><![CDATA[50]]> </BookItem>
<BookItem ISBN="PUOT84747"><![CDATA[20]]> </BookItem>
</Book>
This code gives me all the CDATA sections,
var value = from v in x.Descendants("BookItem").OfType<XCData>()
select (string)v.Value;
How to put where clause based on ISBN ?
How can I read this CDATA using LINQ to XML.

var value = x.DescendantNodes().OfType<XCData>()
.Where(m => m.Parent.Name == "BookItem" && m.Parent.Attribute("ISBN").Value == "PUOT84747")
.ToList();
or
before ToList()
.Select(cdata => cdata.Value.ToString());

var xml = Resource1.String1;
var doc = XDocument.Parse(xml);
var isbn = "SKS84747";
var query = string.Format("BookItem[#ISBN='{0}']", isbn);
var book = doc.Root.XPathSelectElement(query);
if (book != null)
Console.WriteLine(book.Value);
OR
var book =
doc.Root.Descendants("BookItem").Where(
x => x.Attribute("ISBN") != null && x.Attribute("ISBN").Value == isbn).Select(x => x.Value).
FirstOrDefault();
OR
var book = (from item in doc.Root.Descendants("BookItem")
where item.Attributes("ISBN").Any() && item.Attribute("ISBN").Value == isbn
select item.Value).FirstOrDefault();

Related

How to solve error in LINQ: Data is null or empty

I have the following code. I want to check if the result is null with an if condition but it always shows an error. How to solve this?
string StrRefNo = Request.QueryString["ref"];
string[] SMSid = StrRefNo.Split('$');
DownloadsDbEntities db = new DownloadsDbEntities();
var data = (from d in db.SMSLink_Expiry
where d.RefNo == SMSid[0]
&& d.SMSLink.ID == Convert.ToInt32(SMSid[1])
select d).ToList();
if (data.Count > 0)
{
string ss = "yes";
}
The LINQ expression node type 'ArrayIndex' is not supported in LINQ to Entities.
Since the expression can not be translated into SQL, pull it out of the statement
string SMSId0 = SMSid[0];
int SMSId1 = Convert.ToInt32(SMSid[1]);
var data = (from d in db.SMSLink_Expiry
where d.RefNo == SMSId0
&& d.SMSLink.ID == SMSId1
select d).ToList();
This should fix your problem:
string StrRefNo = Request.QueryString["ref"];
string[] SMSid = StrRefNo.Split('$');
var ref = SMSid[0];
var smsLinkId = Convert.ToInt32(SMSid[1]);
DownloadsDbEntities db = new DownloadsDbEntities();
var data = (from d in db.SMSLink_Expiry
where d.RefNo == ref
&& d.SMSLink.ID == smsLinkId
select d).ToList();
if (data.Count > 0)
{
string ss="yes";
}
There are many things Linq does not support, since its translating the query to SQL internally.
For reference: The LINQ expression node type 'ArrayIndex' is not supported in LINQ to Entities
You can try this :
string[] SMSid = StrRefNo.Split('$');
var refno=SMSid[0];
var id=Convert.ToInt32(SMSid[1];
DownloadsDbEntities db = new DownloadsDbEntities();
var data = (from d in db.SMSLink_Expiry
where d.RefNo == refno
&& d.SMSLink.ID == id)
select d).ToList();

convert data of XML file to string lists C#

This is how the XML file could look:
<data>
<subdata>
<datatype id="1" name="data1">
<xdim>2</xdim>
<ydim>1</ydim>
</datatype>
<datatype id="2" name="data2">
<xdim>3</xdim>
<ydim>4</ydim>
</datatype>
</subdata>
</data>
Now, i want the following:
A list(string) with all datatype id's like "1" & "2" in the preview above
A list(string) with all the < xdim > stuff like "2" & "3" above
A list(string) with all the < ydim > stuff like "1" & "4" above
Are there easy methods built in in C# for stuff like this? Or could anyone help me with this question?
Jonas
You can use Descendents method.
This method reads all the child nodes even the nested ones where node name matches with specified string.
var Idstring = MyXml.Descendants("datatype").Select (x=>x.Attribute("Id")).ToList();
var xdimstring = MyXml.Descendants("xdim").Select (x=>x.Value).ToList();
var ydimstring = MyXml.Descendants("ydim").Select (x=>x.Value).ToList();
To Appease your curiosity :)
This how you can get nodes from specifically subdata node.
var Idstring = MyXml.Descendants("Subdata").Descendants("datatype").Select (x=>x.Attribute("Id")).ToList();
var xdimstring = MyXml.Descendants("Subdata").Descendants("xdim").Select (x=>x.Value).ToList();
var ydimstring = MyXml.Descendants("Subdata").Descendants("ydim").Select (x=>x.Value).ToList();
Now let say you have Multiple subdata and you want to read nodes only from first one...Simply use First linq extension method
var Idstring = MyXml.Descendants("Subdata").First().Descendants("datatype").Select (x=>x.Attribute("Id")).ToList();
This works and is fairly neat and simple:
string xml =
#"<data>
<subdata>
<datatype id=""1"" name=""data1"">
<xdim>2</xdim>
<ydim>1</ydim>
</datatype>
<datatype id=""2"" name=""data2"">
<xdim>3</xdim>
<ydim>4</ydim>
</datatype>
</subdata>
</data>";
var xelem = XElement.Parse(xml);
var allIDs = xelem
.Descendants()
.Where (x => x.Attribute("id") != null)
.Select (x => x.Attribute("id").Value)
.ToList();
var allXdims = xelem
.XPathSelectElements("//xdim")
.Select (x => x.Value)
.ToList();
var allYdims = xelem
.XPathSelectElements("//ydim")
.Select (x => x.Value)
.ToList();
Obviously the part at the start is just getting the XML into an XElement. You might want to do this with:
var xelem = XElement.Load(myXmlLocation);
instead.
The easiest way to convert classes to and from XML in C# is XML Serialization
For your example, you could create a class with member variables corresponding to the tags in your XML. When you want to create your XML file, you serialize the class to an XML File.
When your want to read back the information, you deserialize the contents of the XML file back to the class you created.
Here's a more comprehensive article: https://msdn.microsoft.com/en-us/library/58a18dwa(v=vs.110).aspx
You can use:
XDocument doc = XDocument.Load(#"..\myfile.xml");
to load your file in a XDocument object.
Then use XDocument methods to create string lists of the required id values:
var ids = (from a in doc.Descendants("subdata").Elements().Attributes("id")
select a.Value).ToList();
var xids = (from e in doc.Descendants("datatype").Elements("xdim")
select e.Value).ToList();
var yids = (from e in doc.Descendants("datatype").Elements("ydim")
select e.Value).ToList();
var xmlDocument = new XmlDocument();
xmlDocument.LoadXml(
"<data><subdata><datatype id=\"1\" name=\"data1\"><xdim>2</xdim><ydim>1</ydim></datatype><datatype id=\"2\" name=\"data2\"><xdim>3</xdim><ydim>4</ydim></datatype></subdata></data>");
var nodes = xmlDocument.SelectNodes("//datatype");
var first = new List<string>();
var Second = new List<string>();
var third = new List<string>();
foreach (XmlNode node in nodes)
{
first.Add(node.Attributes["id"].Value);
}
nodes = xmlDocument.SelectNodes("//xdim");
foreach (XmlNode node in nodes)
{
Second.Add(node.InnerText);
}
nodes = xmlDocument.SelectNodes("//ydim");
foreach (XmlNode node in nodes)
{
third.Add(node.InnerText);
}
Try something like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication81
{
class Program
{
static void Main(string[] args)
{
string xml =
"<data>" +
"<subdata>" +
"<datatype id=\"1\" name=\"data1\">" +
"<xdim>2</xdim>" +
"<ydim>1</ydim>" +
"</datatype>" +
"<datatype id=\"2\" name=\"data2\">" +
"<xdim>3</xdim>" +
"<ydim>4</ydim>" +
"</datatype>" +
"</subdata>" +
"</data>";
XElement data = XElement.Parse(xml);
var results = data.Descendants("subdata").Elements()
.GroupBy(x => x.Name.LocalName)
.Select(x => new
{
name = x.Key,
value = x.Select(y => (string)y).ToList(),
attributes = x.Attributes()
.Select(y => new {name = y.Name.LocalName, y.Value})
.GroupBy(y => y.name, z => z.Value)
.ToDictionary(y => y.Key, z => z.ToList())
}).ToList();
}
}
}

Pick element from xml

I have this code to pick up foods and foodplaces from XML
Att first i have stored the name of each restuarnt in a string list
and i want to pick the food that this restaurants in the lists reservs
foreach(var restaurant in restaurants)
{
List<foodplace> foodPlaces = (from _foodplaces in xmlDocument.Element("foodplaces").Elements("foodplace")
where _foodplaces.Value == restaurant
select new foodplace
{
day = (from day in _foodplaces.Elements(thisDay)
let list = day.Elements("food").Take(3).ToList()
select new DayOfWeek
{
food1 = (list.Count > 0 ? list[0].Value : string.Empty),
food2 = (list.Count > 1 ? list[1].Value : string.Empty),
food3 = (list.Count > 2 ? list[2].Value : string.Empty)
}).FirstOrDefault()
}).ToList();
The problem is that _foodplaces returns value from xmldoxument that lookslike this
\n\n\n\t the litle inddian \t\n\n\n
and the restuarant value is a string looks like this "the litle indian"
and so the linq statement returns null becuse _foodplace is not restuarant
how to come arround this
To remove whitespace and perhaps consider case sensitivity:
where String.Equals(_foodplaces.Value.Trim(), restaurant, StringComparison.OrdinalIgnoreCase)
string nameToSearch = "Restaurant12";
string xml = File.ReadAllText(<<pathtoxml>>, Encoding.Default);
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
//this depends on your xml structure: i assumed that the attribute of the restaurant is name
XmlNode node = doc.selectSingleNode("foodplaces/foodplace[#name = '"+nameToSearch +"']");
if(node != null){
foreach(XmlNode foodNode in node.selectNodes("food")){
//Do something with the foodnode
//e.g. foodNode.SelectsingleNode("Price").InnerText
}
}
Just set the PreserveWhitespace property of XMLDocument to false before loading xml.
XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = false;
doc.Load("your.xml");

parsing XML content - C#

I have not used XML for very long and need to extract the useful information from an XML response. If there are 2 tags that are the same but have a different name e.g
<lst name = "stack">
<str>Ola</str>
<lst name = "overflow">
<str>Hello</str>
</lst>
</lst>
How would I extract the contents of the tag with name="overflow"?
You can use LINQ To XML:
var result = XDocument.Parse(xml)
.Descendants("lst")
.Where(e => (string) e.Attribute("name") == "overflow")
.Descendants("str")
.Select(x => x.Value)
.FirstOrDefault();
Try this to start:
XPathDocument docNav = new XPathDocument(pathName);
XPathNavigator nav = docNav.CreateNavigator();
XmlNamespaceManager ns = new XmlNamespaceManager(nav.NameTable);
string val = nav.SelectSingleNode(#"/lst/lst[#name='overflow']/str")
These are good resources for simple XPath navigation and .NET XML Parsing:
http://www.w3schools.com/xpath/
http://www.codeproject.com/Articles/52079/Using-XPathNavigator-in-C
You may use the System.Xml.Linq namespace:
var xDoc = XDocument.Parse(xml);
var result = xDoc.Descendants()
.Where(d =>
d.Name == "lst" &&
d.Attributes("name").FirstOrDefault()!=null &&
d.Attributes("name").FirstOrDefault().Value == "overflow")
.FirstOrDefault();
User Linq to xml
var xmlFile = XDocument.Load(someFile);
var query = from item in xmlFile.Descendants("childobject")
where !String.IsNullOrEmpty(item.Attribute("using")
select new
{
AttributeValue = item.Attribute("using").Value
};
You can do it with LINQ to XML:
var doc = XDocument.Load("YourXMLPath.xml");
var content = doc
.Element("lst")
.Elements("lst")
.Where(e=>((string) e.Attribute("name") ?? "")=="overflow")
.Select(e=>e.Element("str").InnerText())
.FirstOrDefault();
LINQ to XML in System.Xml.Linq namespace.
const string xml = #"<lst name = ""stack""><str>Ola</str><lst name = ""overflow""><str>Hello</str></lst></lst>";
XDocument doc = XDocument.Parse(xml);
IEnumerable<XElement> overflow = doc.Root.Elements("lst").Where(x => (string) x.Attribute("name") == "overflow");
XElement firstOverflow = overflow.FirstOrDefault();
string value = firstOverflow.Descendants("str").FirstOrDefault(x => x.Value);

Read XML Attribute

I am actually trying to read this piece of XML.
http://datapoint.metoffice.gov.uk/public/data/val/wxfcs/all/xml/351352?res=3hourly&key=99b9f578-ad3d-446c-9d29-0bbee028b483
I was wondering how I could read only the node Period with the value="2012-11-15Z"
So the one below :
This is the code I use
using (XmlReader reader = XmlReader.Create("http://datapoint.metoffice.gov.uk/public/data/val/wxfcs/all/xml/351352?res=3hourly&key=99b9f578-ad3d-446c-9d29-0bbee028b483"))
{
reader.MoveToContent();
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element
&& reader.Name == "Period")
{
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element &&
reader.Name == "Rep")
{
first.Text = reader.GetAttribute("T");
}
}
}
}
}
What is the way for me to read only this node ?
Should I write
if (reader.NodeType == XmlNodeType.Element
&& reader.Name == "Period" && reader.GetAttribute("value") == "2012-11-15Z")
This doesn't seem to work ..
Can someone help me ?
You can easily do that with LINQ to XML:
XDocument xdoc = XDocument.Load(path_to_xml);
var period = xdoc.Descendants("Period")
.Where(p => (string)p.Attribute("value") == "2012-11-15Z")
.SingleOrDefault();
It will return XElement, but you can select any data from period. E.g. T attributes:
List<int> tList = xdoc.Descendants("Period")
.Where(p => (string)p.Attribute("value") == "2012-11-15Z")
.SelectMany(p => p.Elements())
.Select(rep => (int)rep.Attribute("T"))
.ToList();
var query = xdoc.Descendants("Period")
.Where(p => (string)p.Attribute("value") == "2012-11-15Z")
.SelectMany(p => p.Elements())
.Select(rep => new {
T = (int)rep.Attribute("T"),
D = (string)rep.Attribute("D") })
.ToList();
Last query will return List of strongly-typed anonymous objects with integer property T and string property D:
foreach(var x in query)
// use x.T and x.D
Try using xpath to lookup the value like this
XmlDocument doc = new XmlDocument();
using (XmlReader reader = XmlReader.Create("http://datapoint.metoffice.gov.uk/public/data/val/wxfcs/all/xml/351352?res=3hourly&key=99b9f578-ad3d-446c-9d29-0bbee028b483"))
{
doc.Load(reader);
XmlNodeList list = doc.SelectNodes("//Period[#value='2012-11-15Z']");
Console.WriteLine(list.Count);
}

Categories

Resources