I'm confused by Linq XML query - c#

Here is my XML sample. I want to select SystemSetting's value if ID = 123. But I can't figure out how. How can I select SystemSetting value if id's value equal to 123 ?
<?xml version="1.0" encoding="utf-8" ?>
<Private>
<System>
<ID>123</ID>
<NAME>Test</NAME>
<SystemSetting>128</SystemSetting>
<SystemSettingCS>127</SystemSettingCS>
</System>
<System>
<ID>124</ID>
<NAME>Test2</NAME>
<SystemSetting>128</SystemSetting>
<SystemSettingCS>127</SystemSettingCS>
</System>
<System>
<ID>0</ID>
<NAME>Test</NAME>
<SystemSetting>5</SystemSetting>
<SystemSettingCS>250</SystemSettingCS>
</System>
</Private>
Here's what I tried:
var doc = XDocument.Load(Application.StartupPath+ #"\Settings.xml");
var q = from Ana in doc.Descendants("Private")
from sistem in Ana.Elements("System")
where (int)sistem.Element("ID") == 123
from assetText in Sistem.Elements("System")
select assetText.Element("SystemSetting");
MessageBox.Show(q.ToString());
thnx for help.

I think you're making this more complicated than you need to. I think you just need:
var query = doc.Descendants("Private") // Or just doc.Root
.Elements("System")
.Where(x => (int) x.Element("ID") == 123)
.Select(x => x.Element("SystemSetting"))
.FirstOrDefault();
That will select the first matching element, admittedly. The type of query is then XElement; if you take off the FirstOrDefault() part, it will return an IEnumerable<XElement>, for all matching elements.
If you want just the value instead of the element, you can change the Select to:
.Select(x => (string) x.Element("SystemSetting"))
or
.Select(x => x.Element("SystemSetting").Value)
(The first will return null if there's no SystemSetting element; the second will throw an exception.)

Xpath (System.Xml.XPath) can really help here
var system = doc.XPathSelectElement("//System[ID[text()='123']]");
var val = system.Element("SystemSetting").Value;
or with a single line
var s = (string)doc.XPathSelectElement("//System[ID[text()='123']]/SystemSetting");

Your almost there
var xmlFile = XElement.Load(#"c:\\test.xml");
var query =
from e in xmlFile.Elements()
where e.Element("ID").Value == "123"
select e.Element("SystemSetting").Value;

var q = from s in doc.Descendants("System")
where (int)s.Element("ID") == 123
select (int)s.Element("SystemSetting");
And show result (q will have IEnumerable<int> type):
if (q.Any())
MessageBox.Show("SystemSettings = " + q.First());
else
MessageBox.Show("System not found");

Was a Linq question, but there is an alternate XPath approach, but the class defined below could work in either scenario.
Define a class to read from the parent System element:
public class XSystem
{
public XSystem(XElement xSystem) { self = xSystem; }
XElement self;
public int Id { get { return (int)self.Element("ID"); } }
public string Name { get { return self.Element("NAME").Value; } }
public int SystemSetting { get { return (int)self.Element("SystemSetting"); } }
public int SystemSettingCS { get { return (int)self.Element("SystemSettingCS"); } }
}
Then find your System element that has a child ID element of 123.
int id = 123;
string xpath = string.Format("//System[ID={0}", id);
XElement x = doc.XPathSelectElement(xpath);
Then plug it into the class:
XSystem system = new XSystem(x);
Then read the value you want:
int systemSetting = system.SystemSetting;
XPath is defined with using System.Xml.XPath;

Related

How can i fetch the 'Value' from the keyvalue pair using c#

I would like to fetch the string mentioned in 'Value' for various parameter available under 'Name' using c#.
Here is my current xml as follows:
<DrWatson>
<Sets>
<Set>
<APIParameters>
<Parameter Name="SID_STAGE" Value="101198" Required="true" />
<Parameter Name="SID_QE" Value="Test 91817" Required="true" />
</APIParameters>
</Set>
</Sets>
</DrWatson>
I would like to fetch the '101198' available under 'Value' for Name = SID_STAGE.
Please suggest how can i perform it.
You can parse parameters dictionary (that is natural way to store key-value pairs) with LINQ to XML:
var xdoc = XDocument.Load(path_to_xml);
var parameters = xdoc.Descendants("Parameter")
.ToDictionary(p => (string)p.Attribute("Name"),
p => (string)p.Attribute("Value"));
var stage = parameters["SID_STAGE"];
Keep in mind, that you should check if parameter exists in dictionary before getting it (if it is possible that parameter can not be in your xml):
if (parameters.ContainsKey("SID_STAGE"))
// get parameter value
Also with XPath you can make query more concrete (if it is possible that somewhere will be another Parameter elements):
var xpath = "DrWatson/Sets/Set/APIParameters/Parameter";
var parameters = xdoc.XPathSelectElements(xpath)
.ToDictionary(p => (string)p.Attribute("Name"),
p => (string)p.Attribute("Value"));
var result = XElement.Parse(xmlString)
.Descendants("Parameter")
.First(node => (string)node.Attribute("Name") == "SID_STAGE")
.Attribute("Value");
Console.WriteLine(result.Value); //prints 101198
Will throw an exception of element with this attribute is absent. Consider using FirstOrDefault if you would like another behaviour.
Use a LINQ to XML query:
var xml = XDocument.Load("path...");
var foo = (from n in xml.Descendants("APIParameters")
where n.Element("Parameter").Attribute("Name").Value == "SID_STAGE"
select n.Element("Parameter").Attribute("Value").Value).FirstOrDefault();
Gives:
101198
using System;
using System.Xml.Linq;
using System.Web;
namespace YourProjectName
{
public static class XmlFileRetrieve
{
public static string GetParameterValue(string name)
{
try
{
string path = HttpContext.Current.Server.MapPath("~/YourFolderName/YourXmlFileName.xml");
XDocument doc = XDocument.Load(path);
if (!(doc == null))
{
var parameter = (from el in doc.Root.Elements("Parameter")
where (string)el.Attribute("Name") == name
select (string)el.Attribute("value")).Select(keyvalue => new { name = keyvalue }).Single(); ;
return parameter.name;
}
return "";
}
catch (Exception e)
{string error=e.Message;return "";
}
}
}
}

XML parse nodes and subnodes with LINQ

I do have a XML similar like this
<?xml version="1.0" encoding="UTF-8"?>
<e_schema>
<schema_name value="shema1">
<contact>
<id>1</id>
<firstName>firstname1</firstName>
<lastName>lastname1</lastName>
<department>IT</department>
<emailAddress>lastname1#mydomain.com</emailAddress>
<lineManagerId>22331470</lineManagerId>
<telephone_number>
<number1>0000000000</number1>
<number2>1111111111</number2>
<number3>2222222222</number3>
<retries1>2</retries1>
<retries2>1</retries2>
<retries3>2</retries3>
<numberType1>Mobile</numberType1>
<numberType2>Fixnet</numberType2>
<numberType3>Fixnet</numberType3>
</telephone_number>
</contact>
<contact>
<id>2</id>
<firstName>firstname2</firstName>
<lastName>lastname2</lastName>
<department>SUPPORT</department>
<emailAddress>lastname2#mydomain.com</emailAddress>
<lineManagerId>22331470</lineManagerId>
<telephone_number>
<number1>3333333333</number1>
<number2>4444444444</number2>
<number3>5555555555</number3>
<retries1>2</retries1>
<retries2>1</retries2>
<retries3>2</retries3>
<numberType1>Mobile</numberType1>
<numberType2>Fixnet</numberType2>
<numberType3>Fixnet</numberType3>
</telephone_number>
</contact>
</schema_name>
</e_schema>
now with this piece of code I read each of the contact node and add them to a list
var xmlcontacts = xmlloaded.Descendants("schema_name").Where(node => (string)node.Attribute("value") == comboSchema.SelectedValue.ToString());
foreach (XElement subelement in xmlcontacts.Descendants("contact")) //element is variable
{
contact.Add(new Contact()
{
id = subelement.Element("id").Value,
firstName = subelement.Element("firstName").Value,
lastName = subelement.Element("lastName").Value,
department = subelement.Element("department").Value,
emailAddress = subelement.Element("emailAddress").Value,
lineManagerId = subelement.Element("lineManagerId").Value,
//_phonenumbers = phones
});
}
but I do not have any Idea how I can read the node with the telephone_number
can someone give a hint or a line of code how I can do that!
I assume that _phonenumbers is some kind of collection, e.g. an IEnumerable<PhoneInfo>:
_phoneNumbers = subelement.Element("telephone_number").Elements()
.Where(e => e.Name.LocalName.StartsWith("number").Select(e =>
new PhoneInfo
{
Number = e.Value,
Retries = subelement.Element("telephone_Number").Element(
"retries" + e.Name.LocalName.SubString(5)).Value,
NumberType = subelement.Element("telephone_Number").Element(
"numbertype" + e.Name.LocalName.SubString(5)).Value
})
The code uses a linq expression to create a PhoneInfo instance for each number, and it looks up the corresponding retries and number type.
As a note: The xml structure is quite bad, it would be much better to have all the numbers in <number> tags with the actual number being the content and type retries and type data being attributes of that node.
_phonenumbers = subelement.Descendants("telephone_number")
.Select(x =>
new List<string>() {
(string)x.Element("number1"),
(string)x.Element("number2"),
(string)x.Element("number3")
});
I think you need to loop thru "telephone_number" element inside "contact" element.
Below is the code you can try:
var xmlcontacts = xmlloaded.Descendants("schema_name").Where(node => (string)node.Attribute("value") == comboSchema.SelectedValue.ToString());
foreach (XElement subelement in xmlcontacts.Descendants("contact")) //element is variable
{
contact.Add(new Contact()
{
id = subelement.Element("id").Value,
firstName = subelement.Element("firstName").Value,
lastName = subelement.Element("lastName").Value,
department = subelement.Element("department").Value,
emailAddress = subelement.Element("emailAddress").Value,
lineManagerId = subelement.Element("lineManagerId").Value,
//_phonenumbers = phones
});
foreach (XElement phoneElement in subelement.Descendants("telephone_number"))
{
//add telephone_number details in list here
}
}
I have just added one more foreach inside the "contact" loop

C# Linq XML, check for specific value and parse to array

I have the following XML:
<?xml version="1.0" ?>
<NewDataSet>
<Data>
<ElementDefinition>
<ID>1</ID>
<QUANTITY>0</QUANTITY>
</ElementDefinition>
<ElementDefinition>
<ID>2</ID>
<QUANTITY>1</QUANTITY>
</ElementDefinition>
</Data>
</NewDataSet>
I need to create an array which contains all ElementDefinitions which contain a QUANTITY element with a value other then 0.
I tried:
var f = XDocument.Load(path);
var xe = f.Root.Elements("QUANTITY").Where(x => x.Value != "0").ToArray();
But that doesn't seem to work. With the above XML the array should contain 1 item, but it stays 0.
After that I need to create a string for each ElementDefinition in the array, the string must contain the value of the corresponding ID element.
For that I tried:
foreach (string x in xe)
{
string ID = //not sure what to do here
}
You want something like this:
var ids = f.Root.Descendants("ElementDefinition")
.Where(x => x.Element("QUANTITY").Value != "0")
.Select(x => x.Element("ID").Value);
As you want the ID, it is not very helpful to select all QUANTITY nodes. Instead, select exactly what you specified in your question:
All ElementDefinitions (Descendants("ElementDefinition")), that have a QUANTITY with a Value other than 0 (Where(x => x.Element("QUANTITY").Value != "0"). From the resulting nodes, select the ID (Select(x => x.Element("ID").Value)).
Yo can replace with
var xe = f.Root.Elements("Data/ElementDefinition/QUANTITY").Where(x => x.Value != "0").ToArray();

C# XML Descendants Query

This is my XML structure, which is a list of events that each contains a list of event times. I need to return a list of 'TIME' values, but im stuck on how to get these values (Note that I need to query this list & filter by 'Id')
Code so far:
public IEnumerable<EventFeed> GetEventDatesByEventId(int eventId)
{
return (from feed in xmlDoc.Descendants("Event")
where (int)feed.Element("Id") == eventId
from ev in feed.Elements("Times")
select new EventFeed()
{
EventDate = (DateTime)ev.Element("Time")
}).ToList().OrderByDescending(x => x.EventDate);
}
thanks
kb
Close, you'll need to select the <Times> node first or use Descendants since <Time> is below EventTime:
return (from feed in xmlDoc.Descendants("Event")
where (int)feed.Element("Id") == eventId
from et in feed.Element("Times").Elements("EventTime")
select new EventFeed()
{
EventDate = (DateTime)et.Element("Time")
}).ToList().OrderByDescending(x => x.EventDate);
Sample:
string xml = #"<?xml version=""1.0"" ?>
<Events>
<Event>
<Id>542</Id>
<Times>
<EventTime>
<Time>2011-11-28T14:00:00</Time>
</EventTime>
<EventTime>
<Time>2011-11-30T10:00:00</Time>
</EventTime>
<EventTime>
<Time>2011-11-30T09:00:00</Time>
</EventTime>
</Times>
</Event>
</Events>";
int eventId = 542;
foreach (var evt in GetEvents(XDocument.Parse(xml), eventId)
{
Console.WriteLine("{0}", evt.EventDate);
}
Outputs:
11/30/2011 10:00:00
11/30/2011 09:00:00
11/28/2011 14:00:00
This is straight off the bat and untested but something like this might do it, or at least get you started
xmlDoc.Descendants("Event")
.Where(ev => (int) ev.Element("Id") == eventId)
.SelectMany(ev => ev.Element("Times").Elements("EventTime")
.Select(et => et.Element("Time").Value));
You can alter the final select to build your EventFeed class as follows:
.Select(et => new EventFeed{EventDate = (DateTime)et.Element("Time").Value}));

LINQ to XML via C#

I'm new to LINQ. I understand it's purpose. But I can't quite figure it out. I have an XML set that looks like the following:
<Results>
<Result>
<ID>1</ID>
<Name>John Smith</Name>
<EmailAddress>john#example.com</EmailAddress>
</Result>
<Result>
<ID>2</ID>
<Name>Bill Young</Name>
<EmailAddress>bill#example.com</EmailAddress>
</Result>
</Results>
I have loaded this XML into an XDocument as such:
string xmlText = GetXML();
XDocument xml = XDocument.Parse(xmlText);
Now, I'm trying to get the results into POCO format. In an effort to do this, I'm currently using:
var objects = from results in xml.Descendants("Results")
select new Results
// I'm stuck
How do I get a collection of Result elements via LINQ? I'm particularly confused about navigating the XML structure at this point in my code.
Thank you!
This will return a IEnumerable of anonymous class:
var q = from result in xml.Descendants
select new
{
ID = result.Descendants("ID"),
Name= result.Descendants("Name"),
EmailAddress= result.Descendants("EmailAddress")
};
or if you have defined class `Result, e.g.:
class Result
{
public ID { get; set; }
public Name { get; set; }
public EmailAddress { get; set; }
}
then:
var q = from result in xml.Descendants
select new Result
{
ID = result.Descendants("ID"),
Name = result.Descendants("Name"),
EmailAddress = result.Descendants("EmailAddress")
};
(returns IEnumerable<Result>)
If your Results child elements are only Result elements, then you can get them like this:
var objects = from result in xml.Descendants
select result;
But in this lucky case you can just use xml.Descendants.
If it's not only Result elements, then this will do fine:
var object = from result in xml.Descendants
where result.Name == "Result"
select result;

Categories

Resources