XML data filtering and searching - c#

I have the following chunk of XML code that I can easily generate.
<?xml version="1.0" encoding="utf-8"?>
<sessions>
<session date="14.10.2016" time="0:1" amount="1">
<Folder>C:\Users</Folder>
<Folder>C:\Tes2t</Folder>
<Folder>C:\Asgbsf\Aleksei</Folder>
</session>
<session date="14.10.2016" time="15:40" amount="7">
<Folder>C:\Users</Folder>
<Folder>C:\Tes2taaaa</Folder>
<Folder>C:\Asgbsf\Aleksei</Folder>
</session>
</sessions>
I am searching for data with attribute time 15:40 and date 14.10.2016 using following function
private static IEnumerable<XElement> FindElements(string filename, string date, string time)
{
XElement x = XElement.Load(filename);
return x.Descendants().Where(e => e.Attributes("date").Any(a => a.Value.Equals(date)) &&
e.Attributes("time").Any(a => a.Value.Equals(time)));
}
Function being executed like:
foreach (XElement x in FindElements(pathToXml, "14.10.2016", "15:40"))
Console.WriteLine(x.ToString());
Everything is fine, but the output is
<session date="14.10.2016" time="15:40" amount="7">
<Folder>C:\Users</Folder>
<Folder>C:\Tes2taaaa</Folder>
<Folder>C:\Asgbsf\Aleksei</Folder>
</session>
And I need just the folders, eg.
<Folder>C:\Users</Folder>
<Folder>C:\Tes2taaaa</Folder>
<Folder>C:\Asgbsf\Aleksei</Folder>
How do I achieve this? Help please.

(It seems that I am a little bit late, but..) in some cases like this using Xpath is easier than Linq .
var folders = XDocument.Load(filename)
.XPathSelectElements("//session[#dat‌​e='14.10.2016' and #time='15:40']/Folder");

You are currently returning the Element that has attribute of date and time with these values. What you should add to it is to return its child elements of Folder. You can do this by adding .Elements("Folder") after the .Where.
However, I think you can write your query a bit nicer:
Look for all the sessions that the values of those attriute equal to the given input. Then return the element.Elements("Folder").
I've added the .SelectMany() to flatten the inner list of child elements
string date = "14.10.2016";
string time = "15:40";
var result = (from element in XDocument.Load("data.xml").Descendants("session")
where element.Attribute("date")?.Value == date &&
element.Attribute("time")?.Value == time
select element.Elements("Folder")).SelectMany(item => item).ToList();

Related

c# extract value from nextnode

I have the following xml part and am trying to extract the value where key is known. The example below is a snippet, from a larger xml that contains 1000's of nodes.
<?xml version="1.0" encoding="utf-8"?>
<DictionarySerializer>
<item>
<key>key1</key>
<value>CONTENT1</value>
</item>
<item>
<key>key2</key>
<value>CONTENT2</value>
</item>
</DictionarySerializer>
i assume the above is a string called xml,
then with
XDocument.Parse(xml)
.Descendants("key")
.Where(x => (string)x.Value == "key1")
.FirstOrDefault().NextNode.ToString()
I can get the string <value>CONTENT1</value> But i simply cannot get my head around how to get the value of the value node to to say.
I am afrad it is super simple, and i just are stuck in a coffein loop :-)
XDocument.Parse(xml)
.Descendants("key")
.Where(x => (string)x.Value == "key1")
.FirstOrDefault().Value.ToString()
you should use .Value property instead of .NextNode
If you want to get all keys and values from the XML from all 1000 elemnts. You can use:
Dictionary<string, string> elements = new Dictionary<string, string>();
xml.Root.Elements().ToList().ForEach(xmlElement =>
{
elements.Add(xmlElement.Descendants("key").First().Value,
xmlElement.Descendants("value").First().Value);
});
So, the elements dictionary will contain all of your 1000 nodes.
Try to cast NextNode to XElement and get Value from it.
Considering you can use XPath expressions.
expression = #"//Item[Key='1']/Value"
XmlNodeList nodeList = xmlDocument.SelectNodes(expression);
This would give you the value node(s) of items with Key=1. Just find the value of the desired node.
I believe using XDocument you can also try,
string output = xDocument.XPathEvaluate(expression);

How to delete certain root from xml file?

My '.xml' file looks this way:
<?xml version="1.0" encoding="utf-8"?>
<Requestes>
<Single_Request num="1">
<numRequest>1</numRequest>
<IDWork>1</IDWork>
<NumObject>1</NumObject>
<lvlPriority>Высокий</lvlPriority>
</Single_Request>
<Single_Request num="2">
<numRequest>2</numRequest>
<IDWork>2</IDWork>
<NumObject>2</NumObject>
<lvlPriority>Средний</lvlPriority>
</Single_Request>
<Periodic_Request num="1">
<numRequest>3</numRequest>
<IDWork>23</IDWork>
<pFrequency>23</pFrequency>
<lvlPriority>Низкий</lvlPriority>
<time_service>23</time_service>
<time_last_service>23</time_last_service>
<relative_time>23</relative_time>
</Periodic_Request>
</Requestes>
So I need to delete Single_Request with atribute value equal to sTxtBlock_numRequest.Text. I have tried to do it this way:
XDocument doc = XDocument.Load(FilePath);
IEnumerable<XElement> sRequest = doc.Root.Descendants("Single_Request").Where(
t => t.Attribute("num").Value =="sTxtBlock_numRequest.Text"); //I'm sure, that problem is here
sRequest.Remove();
doc.Save(FilePath);
Unfortunattly, nothing has happanned, don`t know how to solve the problem.
This is why , I am looking forward to your help.
You are comparing attribute value with string literal "sTxtBlock_numRequest.Text". You should pass value of textbox text instead:
doc.Root.Elements("Single_Request")
.Where(t => (string)t.Attribute("num") == sTxtBlock_numRequest.Text)
.Remove();
Note - it's better to use Elements when you are getting Single_Request elements of root, because Descendants will search whole tree, instead of looking at direct children only. Also you can call Remove() without saving query to local variable.

Getting Attribute's value from xml in c#

I have a LINQ expression which gets the XML attribute values from a xml file.
var xml = XElement.Load(#"C:\\StoreServer1.xml");
var query = from e in xml.Descendants("Groups")
where int.Parse(e.Element("Store").Value) == 1500
select e.Element("Store").Attribute("WeekDayStClose").Value;
And the xml file is:
enter<?xml version="1.0" encoding="utf-8" ?>
<Stores>
<Groups Range="000">
<Store WeekDayStClose="210" SatStClose="21" SunStClose="22">1500</Store>
<Store WeekDayStClose="23" SatStClose="24" SunStClose="25">18</Store>
<Store WeekDayStClose="23" SatStClose="24" SunStClose="25">19</Store>
</Groups>
</Stores>
I am only getting the attribute result (value) for first element of 1500. If I search same thing for 18 it doesn't return any result and no exception. Any help appreciated....Plz help!!!
Try this out:-
var xml = XElement.Load(#"C:\\StoreServer1.xml");
var query = xml.Descendants("Groups").Descendants("Store").Where(e => int.Parse(e.Value) == 18).Select(e=> e.Attribute("WeekDayStClose").Value);
You should be more granular, call sub Descendants with Store (XName):
var xml = XElement.Load(#"C:\\New Folder\\StoreServer1.xml");
var query = from e in xml.Descendants("Groups").Descendants("Store")
where int.Parse(e.Value) == 18
select e.Attribute("WeekDayStClose").Value;
Because now you're retrieving only the first Store of each Group which is 1500.
Yes, you have a little error in your code:
You are splitting your xml into group-elements (you have just one group). Then you check if the first store element has the value 1500 (you are not checking if the following store elements have maybe the value 1500)
You need to change your code into the following
var query = from e in xml.Descendants("Store")
where int.Parse(e.Value) == 1500
select e.Attribute("WeekDayStClose").Value;

Querying xml with linq

So I am having a hard time understanding how to use linq in C#. I found some examples but couldn't find one that would match the case I am looking for. Given the following xml:
<?xml version="1.0"?>
<dwml version="1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http
://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://gra
phical.weather.gov/xml/DWMLgen/schema/DWML.xsd">
<head>
<product srsName="WGS 1984" concise-name="time-series" operational-mode="off
icial">
<title>NOAA's National Weather Service Forecast Data</title>
<field>meteorological</field>
<category>forecast</category>
<creation-date refresh-frequency="PT1H">2013-09-18T07:17:35Z</creation-dat
e>
</product>
<source>
<more-information>http://graphical.weather.gov/xml/</more-information>
<production-center>Meteorological Development Laboratory<sub-center>Produc
t Generation Branch</sub-center></production-center>
<disclaimer>http://www.nws.noaa.gov/disclaimer.html</disclaimer>
<credit>http://www.weather.gov/</credit>
<credit-logo>http://www.weather.gov/images/xml_logo.gif</credit-logo>
<feedback>http://www.weather.gov/feedback.php</feedback>
</source>
</head>
</dwml>
I want to print out the creation-date attribute value. The only way I was able to do this was by the code below:
XElement xElement = XElement.Load(XmlReader.Create(new StringReader(xml)));
var nodes = xElement.Elements("head").Elements("product").Elements("creation-date");
foreach (var attr in nodes)
{
Console.WriteLine("value = " + attr.Value);
}
I am sure there is a much better way using queries. I tried playing with the select statements but couldn't get it to work correctly without having to do some manipulation. Would be really nice to just have one query without having to loop through the result set.
String output=xElement.Descendants("creation-date")
.Select(x=>x.Value).First();
That will give you collection of parsed DateTime objects:
var dates = from cd in xdoc.Descendants("creation-date")
select (DateTime)cd;
You can enumerate them:
foreach(DateTime date in dates)
Console.WriteLine(date);
Also if it is possible that other elements besides product can contain creation-date, then you can use following XPath to select creation dates of products only:
xdoc.XPathSelectElements("dwml/head/product/creation-date")
You can merge your values using String.Join method:
Console.WriteLine(String.Join(Environment.NewLine, nodes.Select(x => (string)x)));
But to be clear, it will perform collection enumeration anyway.

Simple XML parsing with LINQ

I would like to parse this XML :
<?xml version="1.0" encoding="Windows-1252" ?>
<TEST>Login inexistant</TEST>
I wrote this code
var result = from item in XElement.Parse(m_strRetour).Descendants("TEST")
select item;
return result.First().ToString();
m_strRetour is a string that contains my XML.
After execution, result is empty.
What am I doing wrong?
TEST seems to be your root node, so it can't be a Descendant.
To get the value out of it you could try this.
var xml = "<?xml version='1.0' encoding='Windows-1252' ?><TEST>Login inexistant</TEST>";
var result = XElement.Parse(xml);
var value = result.Value;
XElement.Parse will return the TEST element itself - which doesn't have any descendants. (Also, there's no benefit in using a query expression here. Whenever you write from x in y select x you should consider whether you couldn't just use y instead...)
You could parse it as an XDocument instead, in which case there would be a TEST descendant... or you could just use the XElement itself.
What are you really trying to achieve though? Does your real XML only have a single element?

Categories