xml xdocument, read attribute - c#

I want to read XML document with help of XDocument. I already search over the internet for the right solution. I found this example, but didnt work like it should.
My XML:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<blabla>
<Infos>
<ConfigurationName>XXConfigurationName</ConfigurationName>
<DateSaved>14.10.2015 10:41:54</DateSaved>
</Infos>
<Configuration>
<DayRoutine>
<DayRoutine ID="4">
<Button>1</Button>
<DayRoutinePoints>
<Point0>00:00:00, 243</Point0>
<Point1>00:00:00, 243</Point1>
<Point2>00:00:00, 243</Point2>
<Point3>00:00:00, 243</Point3>
</DayRoutinePoints>
</DayRoutine>
<DayRoutine ID="3">
<Button>5</Button>
<DayRoutinePoints>
<Point0>00:00:00, 243</Point0>
<Point1>00:00:00, 243</Point1>
<Point2>00:00:00, 243</Point2>
<Point3>00:00:00, 243</Point3>
</DayRoutinePoints>
</DayRoutine>
</DayRoutine>
</Configuration>
</blabla>
And my C# code - updated:
XDocument doci = XDocument.Load(path);
var mijav = from r in doci.Descendants("Configuration").Descendants("DayRoutine").Descendants("DayRoutine").Where(r => (int)r.Attribute("ID") == 4)
select new
{
Button = r.Element("Button").Value,
DataPoints = r.Elements("DayRoutinePoints").Select(c => (string)c.Value).ToList(),
};
My Current C# code dont give me anything. I like to read data from DayRoutine ID="3". How to do that? Because I try to erase "Where(r => (int)r.Attribute("ID")==3)" and I get result from first "DayRoutine". But I like to have data from "second" DayRoutine.
And later I like to read Points. But because it is not every time the same number of points, how to read this points with some loop?
Thanks for help and please ask if you have any question

How I can read points now? It can be points from 0 to 60.
This basic approach gives you the points as XElements.
...
new
{
...
//DataPoints = r.Descendants("DayRoutinePoints").Descendants("Point1"),
DataPoints = r.Elements("DayRoutinePoints").ToList(),
}
Add a .Select(xe => ...) before the ToList to convert to your own class.

Related

LinqToXML: accessing child elements

I trying to figure out a solution for a tiny problem I have, but I didn't have much success in last two days. I've went through many posts here but I failed to find an adequate solution for myself. I know it's probably basic question for you guys, but it seems like I've lost focus and can think clearly about this issue.
So, this is the issue. I have a sample XML below, with the structure I need. What I want is to read this XML, go to the event I want and than read/ store all test elements.
<Config>
<Events>
<Event_1>
<NameOfEvent>SomeName:</NameOfEvent>
<test id="test001">
<xpath>"some xpath"</xpath>
<value>someValue1</value>
<tagName>none</tagName>
</test>
<test id="test002">
<xpath>"some xpath"</xpath>
<value>someValue2</value>
<tagName>none1</tagName>
</test>
<test id="test003">
<xpath>"some xpath"</xpath>
<value>someValue3</value>
<tagName>none2</tagName>
</test>
</Event_1>
</Events>
</Config>
What I`ve done so far is this:
string EventCode="Event_1";
var doc= XDocument.Load(#"C:\new\test\testConfig.xml");
var result = from y in doc.Descendants(EventCode).
Where(y =>(string)y.Element("path").Attribute("id")=="test001"
{
NameOfEvent = y.Element("NameOfEvent").Value,
xpath= y.Element("test").Element("xpath").Value
value =y.Element("test").Element("value").Value,
tag =y.Element("test").Element("tagName").Value
};
Than, I want to use foreach loop, to access all test elements. But, I`m only able to access chiled nodes of first element test.
Can you help with this? Thanks a lot in advance!!!
Assuming your XML has no specific namespaces
var evt = (from el in doc.Descendants("test")
where el.Parent.Name == "Event_1"
group el by el.Parent.Element("NameOfEvent").Value into g
select new {
Name = g.Key,
Tests = g.Select(x => new {
XPath = x.Element("xpath").Value,
Value = x.Element("value").Value,
TagName = x.Element("tagName").Value
})
}).FirstOrDefault();
Console.WriteLine("Event name: " + evt.Name);
foreach (var test in evt.Tests)
{
Console.WriteLine(test.XPath);
Console.WriteLine(test.Value);
Console.WriteLine(test.TagName);
}
Live demo

How to modify XML file in c#?

<Customers>
<Customer1>
<Name>Bobby</Name>
<Age>21</Age>
<Address>Panjim</Address>
</Customer1>
<Customer2>
<Name>Peter</Name>
<Age>32</Age>
<Address>Panjim</Address>
</Customer2>
<Customer4>
<Name>Joel</Name>
<Age>32</Age>
<Address>Mapusa</Address>
</Customer4>
</Customers>
So the thing is I want to delete a particular element and when i delete the first element i.e customer1, I want to update the other elements. I mean I want to make customer3, customer2 and customer2, customer1.
Can anyone please help me achieve this?
What about:
class Program {
static void Main(string[ ] args) {
XDocument doc = XDocument.Load("D:\\file.xml"); //example file
doc.Root.SwitchAndRemove("Customer1");
doc.Save("D:\\file.xml");
}
}
public static class Utilities {
public static void SwitchAndRemove(this XElement customers, XName name) {
var x = customers.Descendants().Where(e => e.Name == name).Select((element, index) => new { element, index }).Single();
int count = 0;
XElement temp = x.element;
foreach (XElement el in customers.Nodes()) {
if (count == x.index + 1) {
temp.RemoveAll();
temp.Add(el.Descendants().ToArray());
temp = el;
}
else
count++;
}
temp.Remove();
}
}
By giving as input your xml the output is the following:
<?xml version="1.0" encoding="utf-8"?>
<Customers>
<Customer1>
<Name>Peter</Name>
<Age>32</Age>
<Address>Panjim</Address>
</Customer1>
<Customer2>
<Name>Joel</Name>
<Age>32</Age>
<Address>Mapusa</Address>
</Customer2>
</Customers>
I'd argue that your problem is not how you could rename your nodes with minimum effort but structure of your XML file.
You said order of customers is not important and apparently customer tag's number is not important, either, since you want to rename the tags upon deletion.
So maybe this structure just creates unnecessary complexity and extra work for you.
Only reason I see you could need the number in tag is to identify the node you are about to remove. Am I right or is there something more to it? If not then you could add random unique identifier (like Guid) to your customer data to remove the right one.
Could save you lot of trouble.
<customers>
<customer>
<guid>07fb-877c-...</guid>
<name>Notch</name>
<age>34</age>
<address>street</address>
</customer>
<customer>
<guid>1435-435a-...</guid>
<name>Sam</name>
<age>23</age>
<address>other</address>
</customer>
<customers>
Say the element you have to delete is Customer1, first of all you can read the complete xml file using one of the XML parsing classes available in c# like XDocument or XmlReader and write to another xml file say "Temp.xml" skipping the Customer1 element completely. This way we have achieved the deletion part.
Next to update, forget the file being XML file and read the entire file to a string, say "xmlstring". Now use the Replace function available with a string data type to replace "Customer2" with "Customer1" and then "Customer3" with "Customer2" and so on.
And now delete your original XML file and write the string "xmlstring" using a stream writer to a file name "YourFileName.xml"
Thats it. Hope this solution works for you. Try this and in case u are unable get this done, share the code which u tried and we shall suggest how to work it out.
taken from your comment that the order does not have to be preserved then you can do this
public static void RemoveCustomer(XElement customers, XElement removeThis){
var last = customeers.Elements().Last();
if(last != removeThis){
foreach(var element in removeThis.Elements()){
element.Value = last.Element(element.Name).Value;
}
}
last.Remove();
}
It effectively substitutes the one to be removed with the last (unless the last should be removed) and thereby eliminates the need for renaming any of the other elements

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;

xml Nodes by Element

Below is an example of the xml file that I need to pull data via C#. This is my first experience with reading xml files and a beginner with xml. Anyone have an example of how I would find/load the fieldorder values for Export_B?
<?xml version="1.0" encoding="utf-8"?>
<Config>
<OutFolderCSV>c:\Output\2012\upload_Files</OutFolderCSV>
<OutFolderImage>c:\Output\2012\NM_Scorecard_Images</OutFolderImage>
<PathOutLogFile>c:\Output\2012\Log\Matches.log</PathOutLogFile>
<FieldSeparator>,</FieldSeparator>
<ExportFile>
<Name>Export_A</Name>
<FieldOrder>matchID</FieldOrder>
<FieldOrder>contactID</FieldOrder>
<FieldOrder>stageID13</FieldOrder>
<FieldOrder>stringScore1a</FieldOrder>
<FieldOrder>xScore1a</FieldOrder>
<FieldOrder>stageID14</FieldOrder>
<FieldOrder>stringScore1b</FieldOrder>
<FieldOrder>xScore1b</FieldOrder>
<FieldOrder>stageID15</FieldOrder>
<FieldOrder>stringScore1c</FieldOrder>
<FieldOrder>xScore1c</FieldOrder>
</ExportFile>
<ExportFile>
<Name>Export_B</Name>
<FieldOrder>matchID</FieldOrder>
<FieldOrder>contactID</FieldOrder>
<FieldOrder>stageID16</FieldOrder>
<FieldOrder>stringScore1a</FieldOrder>
<FieldOrder>xScore1a</FieldOrder>
<FieldOrder>stageID17</FieldOrder>
<FieldOrder>stringScore1b</FieldOrder>
<FieldOrder>xScore1b</FieldOrder>
<FieldOrder>stageID18</FieldOrder>
<FieldOrder>stringScore1c</FieldOrder>
<FieldOrder>xScore</FieldOrder>
</ExportFile>
</Config>
Using LINQ to XML:
var doc = XDocument.Load(#"c:\path\to\file.xml");
var fieldOrders =
from exportFile in doc.Descendants("ExportFile")
where (string)exportFile.Element("Name") == "Export_B"
from fieldOrder in exportFile.Elements("FieldOrder")
select (string)fieldOrder;
I have written an article
http://www.codeproject.com/Articles/33769/Basics-of-LINQ-Lamda-Expressions
on XML using XDocument object.
You can parse the XML easily using
XDocument.Load(filepath)
Please read the section XLinq to parse the objects.
edit :
You can change value of Export_B using the code :
var document = XDocument.Load(filepath)
var exportFiles = document.Descandants("ExportFile");
List<XElement> list = new List<XElement>();
foreach(var element in exportFiles)
{
list.Add(element);
// Now you can do element.Element("Name") to get the name. Put a breakpoint on this, you can get the reference of all underlying objects.
}

Categories