XML query - retrieving values - c#

To my great frustration, I spent half a day to build some queries for an XML document and I don't know anything more than I knew before I started. So, I'm taking the easy way out and ask again for help.
The XML code is like this:
<?xml version="1.0" ?>
<Main>
<alpha Id = "AlphaId_1">
<beta>AlphaId1_Beta</beta>
<gamma>AlphaId1_Gama</gamma>
<delta Type = "A">AlphaId1_DeltaTypeA</delta>
<delta Type = "B">AlphaId1_DeltaTypeB</delta>
<kapa Id="01">
<description>AlphaId1_KapaId1_Descr</description>
<name>AlphaId1KapaId1_Name</name>
<teta>AlphaId1KapaId1_Teta</teta>
</kapa>
<kapa Id="02">
<description>AlphaId1KapaId2_Descr</description>
<name>AlphaId1KapaId2_Name</name>
<teta>AlhaId1KapaId2_Teta</teta>
</kapa>
</alpha>
<alpha Id = "AlphaId_2">
<beta>AlphaId2_Beta</beta>
<gamma>AlphaId2_Gama</gamma>
<delta Type = "A">AlphaId2_DeltaTypeA</delta>
<delta Type = "B">AlphaId2_DeltaTypeB</delta>
<kapa Id="01">
<description>AlphaId2_KapaId1_Descr</description>
<name>AlphaId2KapaId2_Name</name>
<teta>AlphaId2KapaId2_Teta</teta>
</kapa>
<kapa Id="02">
<description>AlphaId1KapaId2_Descr</description>
<name>AlphaId2KapaId2_Name</name>
<teta>AlhaId2KapaId2_Teta</teta>
</kapa>
</alpha>
</Main>
I am looking for a query to retrieve for example the value "AlphaId2_DeltaTypeA".
The second query should retrieve all the description values from every KapaId for a selected AlphaId.
The only code I could come up with is
XDocument xdoc = XDocument.Load(#"doc.xml");
IEnumerable<XElement> list1 = xdoc.Root.Descendants("delta");
var cifmi =
from el in list1
where (string)el.Attribute("Type") == "A"
select el;
foreach (XElement el in cifmi)
{
textBox1.AppendText(el.Value + System.Environment.NewLine);
}
The code finds two values instead of one.

var xDoc = XDocument.Load("Input.txt");
var alpha = (from a in xDoc.Root.Elements("alpha")
let deltas = a.Elements("delta")
let deltaA = deltas.First(x => (string)x.Attribute("Type") == "A")
where (string)deltaA == "AlphaId2_DeltaTypeA"
select a).First();
var descriptions = alpha.Elements("kapa")
.Select(x => (string)x.Element("description")).ToList();
It will only look for <delta> which has both Type="A" and value of AlphaId2_DeltaTypeA. If you only care about value try that one:
var alpha = (from a in xDoc.Root.Elements("alpha")
let deltas = a.Elements("delta")
where deltas.Any(x => (string)x == "AlphaId2_DeltaTypeA")
select a).First();
Update
*alpha Id == "AlphaId_1" and delta Type = "A" and the answer is AlphaId1_DeltaTypeA*
var alpha = (string)xDoc.Root
.Elements("alpha")
.First(x => (string)x.Attribute("Id") == "AlphaId_1")
.Elements("delta")
.First(x => (string)x.Attribute("Type") == "A");

Related

How can I group/sum values in LINQ to XML?

I've been trying to work thru this but I am having problems grouping the data.
I have an XML structure
<FILE>
<PLAN>
<PLAN_ID>001</PLAN_ID>
<PARTICIPANT>
<PARTICIPANT_ID>9999</PARTICIPANT_ID>
<INVESTMENTS>
<INVESTMENT>
<INVESTMENT_ID>ABC</INVESTMENT_ID>
<BALANCE>1000</BALANCE>
<ELECTION>0.00</ELECTION>
</INVESTMENT>
<INVESTMENT>
<INVESTMENT_ID>XYZ</INVESTMENT_ID>
<BALANCE>2000</BALANCE>
<ELECTION>0.00</ELECTION>
</INVESTMENT>
<INVESTMENT>
<INVESTMENT_ID>QWERTY</INVESTMENT_ID>
<BALANCE>3000</BALANCE>
<ELECTION>100.0</ELECTION>
</INVESTMENT>
</INVESTMENTS>
</PARTICIPANT>
</PLAN>
<PLAN>
<PLAN_ID>002</PLAN_ID>
<PARTICIPANT>
<PARTICIPANT_ID>9999</PARTICIPANT_ID>
<INVESTMENTS>
<INVESTMENT>
<INVESTMENT_ID>ABC</INVESTMENT_ID>
<BALANCE>2000</BALANCE>
<ELECTION>0.00</ELECTION>
</INVESTMENT>
<INVESTMENT>
<INVESTMENT_ID>XYZ</INVESTMENT_ID>
<BALANCE>4000</BALANCE>
<ELECTION>0.00</ELECTION>
</INVESTMENT>
<INVESTMENT>
<INVESTMENT_ID>QWERTY</INVESTMENT_ID>
<BALANCE>6000</BALANCE>
<ELECTION>100.0</ELECTION>
</INVESTMENT>
</INVESTMENTS>
</PARTICIPANT>
</PLAN>
</FILE>
I started with just trying to get the SUM of all of the BALANCE elements
var doc = XDocument.Load("test.xml");
var sum = (from nd in doc.Descendants("BALANCE")
select Int32.Parse(nd.Value)).Sum();
Console.WriteLine(sum);
and that worked, giving me 18000. Then I wanted to group the data by the PLAN_ID but I cannot get it to give me other than 0.
var doc = XDocument.Load("test.xml");
var q = from x in doc.Descendants("PLAN")
group x by x.Element("PLAN_ID").Value into gr
select new
{
key = gr.Key,
tot = (from tx in gr.Elements("BALANCE")
select (int)tx).Sum()
};
When I run that I get:
[0] { key = "001", tot = 0 }
[1] { key = "002", tot = 0 }
Where did I go wrong?
The problem is that you're using Elements() when the element you're looking for is deeper into the XML tree than a single level. If you switch to Descendants() within your inner query, then you should get the results you're expecting.
var doc = XDocument.Load("test.xml");
var q = from x in doc.Descendants("PLAN")
group x by x.Element("PLAN_ID").Value into gr
select new
{
key = gr.Key,
tot = (from tx in gr.Descendants("BALANCE")
select (int)tx).Sum()
};
The BALANCE nodes are 3 nodes deeper than the inner nodes of each PLAN node, so this should do the trick.
Personally, I like using the lambda version because it's a bit cleaner, so just for completeness here's the associated solution using the lambda syntax:
var q = doc.Descedants("PLAN")
.GroupBy(x => x.Element("PLAN_ID").Value))
.Select(gr => new
{
key = gr.Key,
tot = gr.Sum(tx => (int)tx.Descendants("BALANCE"))
});

Parse XML with Linq according to 2 values

I would like to know how to parse my xml file in c# with LinQ, I made a lot of research but there isn't my precise case..
So here is my xml code :
<WindowsMediaPlayer>
<Playlist name="playlistdefouf">
<Element>
<type>Audio</type>
<name>lol</name>
</Element>
<Element>
<type>Video</type>
<name>tamere</name>
</Element>
</Playlist>
</WindowsMediaPlayer>
I would like to make a function that verify if a song exists (With type AND name) according to the right playlist too.
For example if I got in parameters playlistname = "playlistdefouf",type = "Audio" and name = "lol" my function will return 1
I already tried to do something but I think I'm lost..
XDocument xmlFile = XDocument.Load(Helper.xmlFolder + "/playlist.xml");
IEnumerable<XElement> elem = xmlFile.Root.Descendants();
IEnumerable<XElement> requete = from d in elem
where d.Name == "Playlist"
&& d.Attribute("name").Value == "playlistdefouf"
select d;
IEnumerable<XElement> requete2 = from d in requete.Descendants()
where d.Name == "Element"
select d;
IEnumerable<XElement> requete3 = from d in requete2.Descendants()
select d;
Here is how to retrieve an IEnumerable of the Playlists that have a specific type and name:
XDocument xmlFile = XDocument.Load("playlists.xml");
var res = from playlist in xmlFile.Root.Elements("Playlist")
where
playlist.Attribute("name").Value == "playlistdefouf" &&
playlist.Element("Element").Element("type").Value == "Audio" &&
playlist.Element("Element").Element("name").Value == "lol"
select playlist;
You can get a count of the playlists by using the Count() extension method
res.Count();
Or you can use the Extension method Any() instead of Count to get a boolean that is more expressive if you want to know if a list contains any elements matching your parameters.
This yields the same result but I personally prefer it structured this way:
var xml = XDocument.Load("playlist.xml");
var result = from playlist in xml.Descendants("Playlist")
where (string)playlist.Attribute("name") == "playlistdefouf"
from song in playlist.Descendants("Element")
where (string)song.Element("type") == "Audio" && (string)song.Element("name") == "lol"
select playlist;
Then you can use the IEnumerable extensions to get the results you want:
var count = result.Count();
var isExisting = result.Any();
var playlist = result.ToList();

Use where condition for retrieving the xml data with C#

I want to fetch the data from an xml file. I am fetching the id of node from the previous page. And on next page I want to display the data from xml of that id. I am passing id of node using query string but when I run my code its give me this error
System.Xml.XmlException: Data at the root level is invalid. Line 1, position 1.
Here is my code
XElement xid = XElement.Parse(Request.QueryString["ID"]);
// var id = Request.QueryString["ID"];
var doc = XDocument.Load(Server.MapPath("~/Data/BlogContent.xml"));
var result = doc.Descendants("post")
.Where(x => x.Element("id") == xid)
.Select(x => new
{
id = x.Element("id").Value,
title = x.Element("title").Value,
Discription = x.Element("Discription").Value,
dt = x.Element("dt").Value,
mnt = x.Element("mnt").Value,
yr = x.Element("yr").Value
}).OrderByDescending(x => x.id).Take(5);
Repeater1.DataSource = result;
Repeater1.DataBind();
Here is my xml
<?xml version="1.0" encoding="utf-8"?>
<content>
<post>
<id>1</id>
<title>fds</title>
<Discription>fdsafsdf</Discription>
<dt>21</dt>
<mnt>6</mnt>
<yr>2013</yr>
</post>
</content>
Please tell me where I am going wrong
You don't indicate the line causing the error, but I bet it's this one:
XElement xid = XElement.Parse(Request.QueryString["ID"]);
Most likely "ID" in your query string is an identifier of some sort, not XML - hence the error.
Something like this is what you want:
string xid = Request.QueryString["ID"];
Then you can use it in your where clause.
Also, there's an error in your where clause - you're trying to compare an XElement to a value - you need to get the value of the XElement using it's Value property:
Where(x => x.Element("id").Value == xid)
XElement.Value returns a string - so simply take the string value from the query string and use it in the comparison in your where clause.
Everything Put Together
string xid = Request.QueryString["ID"];
var doc = XDocument.Load(Server.MapPath("~/Data/BlogContent.xml"));
var result = doc.Descendants("post")
.Where(x => x.Element("id").Value == xid)
.Select(x => new
{
id = x.Element("id").Value,
title = x.Element("title").Value,
Discription = x.Element("Discription").Value,
dt = x.Element("dt").Value,
mnt = x.Element("mnt").Value,
yr = x.Element("yr").Value
}).OrderByDescending(x => x.id).Take(5);
Repeater1.DataSource = result;
Repeater1.DataBind();

Linq to xml Select statement

I'm trying to figure out how to do a select statement using linq to xml. I'd like to return the ServerTypes if the DeploymentType equals a specific value (Enterprise9999).
XML:
<Deployments>
<Deployment>
<DeploymentType>Enterprise9999</EnterpriseDeploymentType>
<Servers>
<DeploymentServer>
<ServerType>WindowsServer</ServerType>
</DeploymentServer>
<DeploymentServer>
<ServerType>LinuxServer</ServerType>
</DeploymentServer>
</Servers>
</Deployment>
<Deployment></Deployment>
<Deployment></Deployment>
</Deployments>
Here's what I have so far in the code. I'm sure I'm going about this the wrong way:
XDocument xmlDoc = XDocument.Load(#xmlFile);
IEnumerable<XElement> xlDeployments = from depRows in xmlDoc.Descendants("Deployments")
select depRows;
var deploy = xlDeployments.Descendants("Deployment");
foreach (var dep in deploy)
{
if (dep.Element("DeploymentType").ToString() == "Enterprise9999")
{
MessageBox.Show(dep.Elements("ServerType").ToString());
}
}
Is a namespace required for a select statement?
I've changed you're enclosing tag </EnterpriseDeploymentType> to </DeploymentType>
XDocument xmlDoc = XDocument.Load(#xmlFile);
var deployments = xmlDoc.Descendants("Deployment")
.Where(dep => dep.Element("DeploymentType") != null
&& dep.Element("DeploymentType").Value == "Enterprise9999");
var servers = deployments.Descendants("ServerType")
.Select(node => node.Value);
Console.WriteLine(string.Join(Environment.NewLine, servers));
prints:
WindowsServer
LinuxServer
Assuming you've corrected your XML as per my comment, you can use the following single query: -
var nodes = from n in xml.Descendants("DeploymentType")
.Where(x => x.Element("EnterpriseDeploymentType").Value.Equals("Enterprise9999"))
select n.Descendants("Servers").Descendants("ServerType").Select(s => s.Value);
Which will give you:
WindowsServer
LinuxServer

Trying to read XML attributes via LINQ

xDoc variable loads the XML content but I am not able to retrieve any information. It comes back NULL:
var xDoc = XDocument.Load(Config.CredentialFileName);
//method 1
IEnumerable<XElement> rows = from row in xDoc.Descendants("domain")
where (string)row.Attribute("name") == "TEST"
select row;
//method 2
var list = xDoc.Descendants("domain")
.Select(d => new
{
name = d.Attribute("name").Value,
username = d.Attribute("username").Value,
password = d.Attribute("password").Value //,
})
.Where(a => a.name == "TEST")
.ToList();
XML file:
<domains>
<domain name="TEST" userName="test" password="tSEvmlsmwEkjSxUwrCVf3G6"/>
</domains>
Thank you
Your first method works just fine with xml you provided. Make sure you are parsing xml with exactly same structure. Also check that you have at least one domain element with name equal to TEST. And make sure you don't have namespaces defined in your xml.
Second method has typo in userName attribute name (you have lower case username):
var list = xDoc.Descendants("domain")
.Select(d => new {
name = d.Attribute("name").Value,
username = d.Attribute("userName").Value, // <-- typo here
password = d.Attribute("password").Value
})
.Where(a => a.name == "TEST")
.ToList();
Also, I'd recommend to use casting instead of reading node Value property, because getting this property will throw an exception if node not exist.
var domains = from d in xDoc.Descendants("domain")
let name = (string)d.Attribute("name")
where name == "TEST"
select new {
Name = name,
Username = (string)d.Attribute("userName"),
Password = (string)d.Attribute("password")
};
See below.
var xDoc= XElement.Load(Config.CredentialFileName);
var result = xDoc.Elements("domain").Where(x => x.Attribute("name").Value.Equals("TEST")).ToList();

Categories

Resources