c# Reading XML with XElement - c#

When I run the following code and step through it with a break point and look at temp I see "Empty, Enumeration yielded no results" and the MessageBox.Show never fires. I'm trying to pull everything under Season no="1"
XElement sitemap = XElement.Load(#"http://services.tvrage.com/feeds/episode_list.php?sid=" + this.showID);
IEnumerable<XElement> temp = from el in sitemap.Elements("Season")
where (string)el.Attribute("no") == "1"
select el;
foreach (XElement el in temp)
{
MessageBox.Show("found something");
}
This is the XML that's being loaded:
http://services.tvrage.com/feeds/episode_list.php?sid=6312

You're looking for elements called Season directly under the root element... whereas your XML looks like this:
<Show>
<name>The X-Files</name>
<totalseasons>9</totalseasons>
<Episodelist>
<Season no="1">
<episode>
...
If you want to look for all descendant elements with a given name, use Descendants instead of Elements. That certainly finds elements in the example XML you've given.

Related

I want to create an array containing my xmldocument nodes in c#

Hello I have created an xml file with motivational quotations, and I want to read those quotations into an array.
Here is what my xml file looks like:
<?xml version="1.0" encoding="utf-8" ?>
<MotivationalQuotes>
<quotation>
<quote>Life is about making an impact, not making an income</quote>
<author>Kevin Kruse</author>
</quotation>
<quotation>
<quote>Whatever the mind of man can conceive and believe, it can achieve</quote>
<author>Napoleon Hill</author>
</quotation>
</MotivationalQuotes>
I am trying to store each individual quotation (without the author) into an array, so far I have the below code working - which creates a message box and iterates through the xml file displaying the text from each quotation.
1) How can I modify this code to create a string array, where each item in the array is a quotation (i.e. each item in the array is the contents that is currently being displayed to the messagebox in my foreach loop?
2) how do I return a random item from the array, once it is created?
3) As an extension to my question... my xml file only has motivational quotes in at the moment, but it will have more inspirational, funny etc... how can I specify to only include quotations into the array if they are inside the MotivationalQuotes tag.
Thanks for the help!
public void motivate()
{
XmlDocument doc = new XmlDocument();
doc.Load("quotations.xml");
XmlNode Node = doc.DocumentElement;
foreach (XmlNode Node1 in Node.ChildNodes)
{
MessageBox.Show(Node1.FirstChild.InnerText);
}
}
You should use XDocument and LINQ.
To get all quotes
using System.Xml.Linq;
var quotes = XDocument
.Load("quotations.xml")
.Descendants("quote")
.Select(q => q.Value)
.ToArray();

XDocument LINQ search based on attribute

I have an XML document which I load from the disk
XDocument events = XDocument.Load("Content/GameData/events.xml");
The contents of this xml are the following:
<?xml version='1.0' encoding='UTF-8'?>
<Events>
<level1>
<NarrationEvent code="lvl1_fridge">
I can't even remember when I last ate.
I am not hungry though.
</NarrationEvent>
<NarrationEvent code="lvl1_tv">
Why do I even have a TV?
Oh right, I use it as a screen for my laptop.
</NarrationEvent>
<NarrationEvent code="lvl1_bed">
Oh man, I am beat.
</NarrationEvent>
<NarrationEvent code="lvl1_computer">
Oh, look at that. The project has been compiled.
</NarrationEvent>
</level1>
<level2>
</level2>
<level3>
</level3>
<level4>
</level4>
<cave>
</cave>
</Events>
I use this code here supposedly select the appropriate NarrationEvent element, based on its attribute "code"
IEnumerable<XElement> v =
(from narrationEvent in events.Elements("NarrationEvent")
where (string)narrationEvent.Attribute("code") == code
select narrationEvent);
foreach (XElement page in v)
{
//Console.WriteLine("ff");
narration.Add(page.Value);
}
This returns nothing, my XElement Ienumerable is empty. I used breakpoints and the code value is passed to this method just fine. e.g. "lvl1_bed"
What is wrong with this code?
You can use the Descendants-Method to get your NarrationEvent-Element. I have updated your code accordingly.
IEnumerable<XElement> v = from narrationEvent in events.Descendants("NarrationEvent")
where narrationEvent.Attribute("code").Value == code
select narrationEvent;

Remove Last 30 Days Nodes from XML Document using linq

I have XML Document like
<Records>
<Record>
<Event>Home Value Submits Page 2</Event>
<Date>17-Mar-14 4:49:32 PM</Date>
</Record>
<Record>
<Event>Hm Value Submits Hm Pg</Event>
<Date>17-Mar-14 4:54:36 PM</Date>
</Record>
</Records>
I need to delete last 30 Days nodes from XML Document.
I am using this code but it's not working,
var xelement = XElement.Load(Server.MapPath("~/XMLStorage/DataBase.xml"));
var value30days =
from nm in xelement.Elements("Record")
where (DateTime)nm.Element("Date") <= DateTime.Now && (DateTime)nm.Element("Date") >= DateTime.Now.AddDays(-30)
select nm;
foreach (XElement xEle in value30days)
{
xEle.Remove();
}
xelement.Save(Server.MapPath("~/XMLStorage/DataBase.xml"));
Please Give some solutions.
This is one of those fun problems caused by changing a collection while enumerating/querying it. As soon as you try to remove the first item you break the query.
Try this:
foreach (XElement xEle in value30days.ToArray())
{
xEle.Remove();
}
The ToArray call will ensure that the entire set of results is returned before you start modifying the XML content. You can then iterate through the array and delete as many of those items as you like without the loop breaking.

LINQ: How to return all child elements?

For an application I am working on, I have to display data from an XML File. There's a few transformations being done, but eventually the end result will be displayed in a treeview. When a user then clicks on a node, I want to pop up the details in a listview.
When no node has been selected, I basically use LINQ to grab the details of the first item I encounter.
Here's a simplified version of my XML
<root>
<parent label="parent1">
<child label="child1">
<element1>data</element1>
<element2>data</element2>
...
</child>
<child label="child2">
<element1>data</element1>
<element2>data</element2>
...
</child>
</parent>
</root>
And here's the code used to grab it (After selecting the parent-node that the treeview has been set to by means of an XPAthSelectStatement):
protected void listsSource_Selecting(object sender, LinqDataSourceSelectEventArgs e)
{
XElement rootElement = XElement.Load(MapPath(TreeSource.DataFile));
rootElement = rootElement.XPathSelectElement("//parent[#label='parent1']");
XElement parentElement;
parentElement = rootElement;
var query = (from itemElement in parentElement.Descendants("child")
select new
{
varElement1 = itemElement.Element("element1").Value,
varElement2 = itemElement.Element("element2").Value,
...
}).Take(1);
e.result = Query;
}
This works a treat, and I can read out the varElement1 and varElement2 values from there. However, when I try and implement a similar mechanism for when the user actually did select a node, I seem to run into a wall.
My approach was to use another XPatchSelectStatement to get to the actual node:
parentElement = rootElement.XPathSelectElement("//child[#label='" + tvwChildren.SelectedNode.Text + "']");
But I am kind of stumped on how to now get a proper LINQ query built up to read in all elements nested under the child node. I tried using parentElement.Elements(), but that was yielding an error. I also looked at using Nodes(), but with similar results.
I suppose I could use a foreach loop to access the nodes, but then I'm not sure how to get the results into a LINQ query so I can return the same e.Result = query back.
I'm fairly new to LINQ, as you might have guessed, so any hints would be very much appreciated.
Here's the query that will give you the child element (given that there is only one child element with the specified label):
var childElement = rootNode.Descendants("child")
.Single(e=>e.Attribute("label").Value == "child1");
If you have more than one child elements with label="child1" but those elements are under different parent elements you can use the same approach to get first the parent element and then the child element.
Having the above, you can use this query to get all element nodes under the child node:
var elements = childElement.Descendants().Select(e=>e.Value);
I think data binding is much easier in this case.
XDocument doc = XDocument.Load(filePath);
if (doc.Root == null)
{
throw new ApplicationException("invalid data");
}
tvwChildren.Source=doc;
But if you want in this way hope following one helps(not the exact solution)
XElement root = XElement.Load("Employees.xml");
TreeNode rootNode = new TreeNode(root.Name.LocalName);
treeView1.Nodes.Add(rootNode);
foreach(XElement employee in root.Elements())
{
TreeNode employeeNode = new TreeNode("Employee ID :" + employee.Attribute("employeeid").Value);
rootNode.Nodes.Add(employeeNode);
if (employee.HasElements)
{
foreach(XElement employeechild in employee.Descendants())
{
TreeNode childNode = new TreeNode(employeechild.Value);
employeeNode.Nodes.Add(childNode);
}
}
}
And you can try Resharper tool for create better linq statements. It shows possible ones and you can easily convert each for,foreach loops into linq statements.
I'm not entirely sure I understand what you're trying to do, but it sounds like it could be this:
var data =
from p in xml.Root.Elements("parent")
where p.Attribute("label").Value == "parent1"
from c in p.Elements("child")
where c.Attribute("label").Value == "child2"
from d in c.Elements()
select d.Value;
Let me know if that helps.
Using this Xml library you can write your XPath like:
XElement child = rootElement.XPathElement(
"//parent[#label={0}]/child[#label={1}]", "parent1", "child2");

LINQ to XML: Defer selection of children in Silverlight C#?

I have the following XML Document being loaded into C# Silverlight:
<parent>
<son name="Jim">
<grandson>Billy</grandson>
<granddaughter>Sue</granddaughter>
</son>
<daughter name="Sally">
</daughter>
</parent>
I'd like to do a LINQ query so that I query parent and get a list of "son" and "daughter" nodes only. When I get to a node of type "son", I want to do another query for its own children.
I've tried this:
IEnumerable<XElement> Children =
from childNode in parents.Descendants()
select (XElement)childNode ;
foreach(XElement childNode in Children){
// other code
}
but that gives me everything (son, daughter, grandson, granddaughter).
What I'd like to do is something like this:
foreach(XElement childNode in Children){
switch(childNode.Name.ToString()){
case "son":
// look for "grandson" and "granddaughter" as children of "son" now
break;
case "daughter":
// don't look for anything
break;
}
}
So Basically, I only want the first level of children returned in the query, and I will query for the rest later on.
I'm not sure if it should be done in the original LINQ query, in the foreach condition, or what. I don't have control over the XML document format so I can't change it to something better. Thanks!
If I understand your question correctly you need to use the Elements function:
var sons_qry = from son in parents.Elements()
select son;
var grandsons_qry = from grandson in sons_qry.Descendants()
select grandson;

Categories

Resources