C# reading xml inside certain node - c#

I need help. I'm trying to figure out a way to read inside a bracket like this one:
<group id = "56">
<name>Counter</name>
</group>
In the code, there are mulitiple places where the same pattern comes back, and I would like to get all the group id number's and their name.
This is my code:
XDocument doc = XDocument.Parse(_XmlFile);
var results = doc.Descendants("group").Select(x => new
{
id = (int)x.Attribute("id"),
name = x.Attribute("name").Value,
}).ToList();
Console.WriteLine(results);
Thanks

Your code looks quite OK, but name is an element and not an attribute, so it should be
XDocument doc = XDocument.Parse(_XmlFile);
var results = doc.Descendants("group").Select(x => new
{
id = (int)x.Attribute("id"),
name = (string)x.Element("name"),
}).ToList();
foreach (var x in results)
Console.WriteLine("id: {0} name: {1}", x.id, x.name);

Use GetElementsByTagName method.
Here is the microsoft article explaining it with examples.
https://msdn.microsoft.com/en-us/library/dc0c9ekk(v=vs.110).aspx

"Name" is not an attribute, but a child node. The solution is something like this:
XDocument doc = XDocument.Parse(_XmlFile);
var results = doc.Descendants("group").Select(x => new
{
id = int.Parse(x.Attribute("id").Value),
name = x.Descendants("name").First().Value
}).ToList();

Related

C# deserialize xml using linq

I have the following xml file
<?xml version="1.0" encoding="utf-8"?>
<Launchpad>
<Shortcuts>
<Shortcut Id="1">
<Type>Folder</Type>
<FullPath>C:\bla\bla\bla</FullPath>
<Name>Proximity</Name>
</Shortcut>
<Shortcut Id="2">
<Type>Folder</Type>
<FullPath>C:\bla</FullPath>
<Name>Visual Studio 2017</Name>
</Shortcut>
</Shortcuts>
</Launchpad>
I am trying to deserialize to an object like this: (Tried query syntax first, didn't work either)
XDocument xd = XDocument.Load(FullPath);
// query syntax
//var shortcuts = (from s in xd.Descendants("Shortcuts")
// select new Shortcut()
// {
// Id = Convert.ToInt32(s.Attribute("Id")),
// TypeOfLink = GetTypeFromString(s.Descendants("Type")
// .First()
// .Value),
// FullPathToTarget = s.Descendants("FullPath")
// .First()
// .Value,
// Name = s.Descendants("Name").First().Value,
// }).ToList();
// method syntax
List<Shortcut> shortcuts = xd.Descendants("Shortcuts")
.Select(s =>
new Shortcut()
{
//Id = Convert.ToInt32(s.Attribute("Id")),
TypeOfLink = GetTypeFromString(s.Descendants("Type")
.First().Value),
FullPathToTarget = s.Descendants("FullPath")
.First().Value,
Name = s.Descendants("Name")
.First().Value,
}).ToList();
return shortcuts;
For some reason I only get a single shortcut object in the list. Also, for some reason, the s.Attribute("Id") is null.
If anyone has any suggestions to improve the linq query or why the attribute is not working it would be a great help
You have to read .Descendants("Shortcut") instead of .Descendants("Shortcuts").
Something like this:
List<Shortcut> shortcuts = xd.Descendants("Shortcut").Select(s =>
new Shortcut()
{
Id = s.Attribute("Id").Value,
TypeOfLink = s.Descendants("Type").First().Value,
FullPathToTarget = s.Descendants("FullPath").First().Value,
Name = s.Descendants("Name").First().Value,
}).ToList();
I get the full list by selecting the Shortcut as a descendant of Shortcuts.
Also, ID is an XAttribute so you cant convert it to int.
You need to use Value to get the attributes value.
XDocument xd = XDocument.Load(ms);
XElement root = xd.Document.Root;
var list = root.Descendants("Shortcuts").Descendants("Shortcut").Select(x =>
new Shortcut()
{
Id = Convert.ToInt32(x.Attribute("Id").Value),
TypeOfLink = GetTypeFromString(x.Descendants("Type")
.First().Value),
FullPathToTarget = x.Descendants("FullPath")
.First().Value,
Name = x.Descendants("Name").First().Value
}).ToList();

How to extract xml child element

I am trying to figure out the code to extract xml child (I think this is worded correctly) elements. I have searched and tried many samples but cannot find how to drill down to pick out the section I want and return the information I need. Maybe I all I need is someone to define the data I am trying to pull so I can read up on the issue, of course any code would be very helpful and I will figure it out from there. Thanks in advanced for any help!
Here is the xml file. I am trying to run an if statement to find the section named <STATISTICTYPE>PVCAP_CharactersSaved</STATISTICTYPE> and return the <JOBNAME>,<TIMEDELTA>,<VALUESUM>.
<?xml version="1.0" encoding="utf-8"?>
<PVCAPTURESTATISTICCONTAINTER xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<PVCAPTUREJOBSTATISTICS>
<PVCAPTURESTATISTICSUMMARY>
<STATISTICTYPE>PVCAP_CharactersSaved</STATISTICTYPE>
<STATISTICNAME>Characters saved</STATISTICNAME>
<JOBID>24</JOBID>
<JOBNAME>HEAT FILES</JOBNAME>
<TIMEDELTA>422</TIMEDELTA>
<VALUESUM>25432</VALUESUM>
</PVCAPTURESTATISTICSUMMARY>
<PVCAPTURESTATISTICSUMMARY>
<STATISTICTYPE>PVCAP_CharactersSaved_NoMM</STATISTICTYPE>
<STATISTICNAME>Characters saved (no match and merge)</STATISTICNAME>
<JOBID>24</JOBID>
<JOBNAME>HEAT FILES</JOBNAME>
<TIMEDELTA>422</TIMEDELTA>
<VALUESUM>25432</VALUESUM>
</PVCAPTURESTATISTICSUMMARY>
</PVCAPTUREJOBSTATISTICS>
<DOCUMENTCOUNT>762</DOCUMENTCOUNT>
<PAGECOUNT>3194</PAGECOUNT>
<IMAGECOUNT>3194</IMAGECOUNT>
<VERSION>2.0</VERSION>
</PVCAPTURESTATISTICCONTAINTER>
You can use LINQ to XML, particularly the XElement class.
var element = XElement.Parse(xmlStr).Element("PVCAPTUREJOBSTATISTICS")
.Elements("PVCAPTURESTATISTICSUMMARY")
.First(c => c.Element("STATISTICTYPE").Value == "PVCAP_CharactersSaved")
var jobName = element.Element("JOBNAME").Value;
var timeDelta = element.Element("TIMEDELTA").Value;
var valueSum = element.Element("VALUESUM").Value;
You'll want to add in some error handling and whatnot here, but this should get you going in the right direction.
You can do something like this:
XElement res = XElement.Parse(xmlResult);
foreach(var elem in res.Element("PVCAPTUREJOBSTATISTICS").Elements("PVCAPTURESTATISTICSUMMARY"))
{
if (elem.Element("STATISTICTYPE").Value.Equals("PVCAP_CharactersSaved", StringComparison.Ordinal))
{
string jobName = elem.Element("JOBNAME").Value;
string timeDelta = elem.Element("TIMEDELTA").Value;
string valueSum = elem.Element("VALUESUM").Value;
}
}
You can use XDocument and LINQ-to-XML to do that quite easily, for example :
string xml = "your xml content here";
XDocument doc = XDocument.Parse(xml);
//or if you have the xml file instead :
//XDocument doc = XDocument.Load("path_to_xml_file.xml");
var result = doc.Descendants("PVCAPTURESTATISTICSUMMARY")
.Where(o => (string) o.Element("STATISTICTYPE") == "PVCAP_CharactersSaved")
.Select(o => new
{
jobname = (string) o.Element("JOBNAME"),
timedelta = (string) o.Element("TIMEDELTA"),
valuesum = (string) o.Element("VALUESUM")
});
foreach (var r in result)
{
Console.WriteLine(r);
}

XML parsing issue in WinStoreApp

i just stuck in an issue when ever i parse my XML like this using Xdocument :
XDocument xmldoc = XDocument.Load(datafromxml);
var data = from query in xmldoc.Descendants("Chapter")
select new MyEntityclass
{
Sampledata = (string)query.Element("SubChapter")
};
i got only one tag inner value from this. i.e from the first tag value only. remaining are skipped.
My XML is like :
<Chapter>
<SubChapter ChapterID="1"><![CDATA["Some data here 1"]]></SubChapter>
<SubChapter ChapterID="2"><![CDATA["Some data here 2"]]></SubChapter>
<SubChapter ChapterID="3"><![CDATA["Some data here 3"]]></SubChapter>
</Chapter>
when i checked in a debug i just got the value of "chapterid : 1". please help me to sort out this. thanks
Your query now only retreives (iterates) the outer node.
You need something like (untested)
var data = from query in xmldoc.Descendants("Chapter")
from chapter in query.Elements("SubChapter") // note the 's'
select new MyEntityclass
{
Sampledata = (string)chapter
};
var data = xmlDoc.Root
.Elements("SubChapter")
.Select(x => new MyEntityclass { Sampledata = (string)x });

linq query for descendants of n.element

Hi can anyone help with a linq query, normally I populate my data grid like so from my client side for a GET request to the webservice:
{
string uri = "http://localhost:8002/Service/Customer";
XDocument xDoc = XDocument.Load(uri);
var customer = xDoc.Descendants("Customer")
.Select(n => new
{
CustomerID = n.Element("CustomerID").Value,
Firstname = n.Element("FirstName").Value,
Surname = n.Element("LastName").Value,
Age = n.Element("Age").Value,
//Time = DateTime.Parse(n.Element("TimeAdded").Value)
})
.ToList();
dataGrid1.ItemsSource = customer;
}
Which works fine but now I have linked customers to hire dates and my xml looks like so :
<ArrayOfCustomer>
<Customer>
<CustomerID>1</CustomerID>
<FirstName>G</FirstName>
<LastName>Graam</LastName>
<Age>27</Age>
<CustomerHireDate>
<HireDate>
<HireFromDate>15.07.2012</HireFromDate>
<HireToDate>29.07.2012</HireToDate>
</HireDate>
</CustomerHireDate>
</Customer>
</ArrayOfCustomer>
So far im stuck at the below method of trying to populate a datagrid with descendants of descendants:
string uriShowCarHires = "http://localhost:8002/Service/Customer/{anything}";
string Uri = uriShowCarHires.Replace("{anything}", textBox1.Text);
XDocument xDoc = XDocument.Load(Uri);
foreach (var node in xDoc.Descendants("Customer"))
{
\\..... how do you get the descendants of descendants for each n.element?
}
Im not sure if this will even populate a datagrid the way im thinking, i was hoping to avoid getting an "array" inside one of the datagrids cells. Im looking for an output abit like this:
Name etc | HireFromDate | HireToDate
G 09.12.2012 01.01.2013
If anyone could help would be grateful thanks
I think you are looking for something like this (it isn't the most effecient, but it should work):
var customer = xDoc.Descendants("Customer")
.Select(n => new
{
Firstname = n.Element("FirstName").Value,
Surname = n.Element("LastName").Value,
HireFromDate = n.Element("CustomerHireDate")
.Descendents("HireDate").First()
.Descendents("HireFromDate").First().Value,
HireFromDate = n.Element("CustomerHireDate")
.Descendents("HireDate").First()
.Descendents("HireToDate").First().Value
})
.ToList();

c# code for getting xml elements

I have following xml file:
<os:tax>
<os:cat name="abc" id="1">
<os:subcat name="bcd" id="11">
<os:t name="def" id="111">
<os:cut name="hello" id="161" cutURL="/abc/a.html"/>
<os:cut name="hello2" id="162" cutURL="/abc1/a1.html"/>
<os:cut name="hello3" id="163" cutURL="/abc4/a3.html"/>
</os:t>
</os:subcat>
</os:cat>
<os:cat name="def" id="2">
<os:subcat name="bcd" id="22">
<os:t name="def" id="222">
<os:cut name="hello" id="171" cutURL="/abcs/a.html"/>
<os:cut name="hello2" id="172" cutURL="/abcs1/a1.html"/>
<os:cut name="hello3" id="173" cutURL="/abcs4/a3.html"/>
</os:t>
</os:subcat>
</os:cat>
</os:tax>
Its a bigger file with lot of os:cat under it. I need to get string value for:
os:cat -> id , name
os:subcat -> id, name
os: t -> id, name
os: cut -> id, name, cutURL
I have this so far:
XmlNodeList tax = xmlDoc.GetElementsByTagName("os:tax");
foreach (XmlNode node in tax)
{
XmlElement cat = (XmlElement)node;
// than get string values here?
}
Is this correct? Can anyone show me efficient way to do this? Or right way to do this easily?
Here's a sample for LINQ to XML - but I strongly suggest you look for full LINQ to XML tutorials. (And get to grips with the rest of LINQ...)
(EDIT: I hadn't spotted the t part before.)
XDocument doc = XDocument.Load("tax.xml");
XNamespace os = "http://something"; // You haven't included the declaration...
foreach (XElement cat in doc.Descendants(os + "cat"))
{
int catId = (int) cat.Attribute("id");
string catName = (string) cat.Attribute("name");
foreach (XElement subcat in cat.Elements(os + "subcat"))
{
int subId = (int) subcat.Attribute("id");
string subName = (string) subcat.Attribute("name");
foreach (XElement t in subcat.Elements(os + "t"))
{
int tId = (int) t.Attribute("id");
string tName = (string) t.Attribute("name");
foreach (XElement cut in t.Elements(os + "cut"))
{
string cutId = (int) cut.Attribute("id");
string cutName = (string) cut.Attribute("name");
string cutUrl = (string) cut.Attribute("cutURL");
// Use the variables here
}
}
}
}
This assumes there's only one subcat for each cat - I don't know if that's correct.
You may want to express this as a LINQ query instead... it depends on what you need to do.
Here's a LINQ query version - having looked at everything you're using, I think this makes more sense:
XDocument doc = XDocument.Load("tax.xml");
XNamespace os = "http://something"; // You haven't included the declaration...
var query = from cat in doc.Descendants(os + "cat")
from subcat in cat.Elements(os + "subcat")
from t in subcat.Elements(os + "t")
from cut in t.Elements(os + "cut")
select new
{
CatId = (int) cat.Attribute("id"),
CatName = (string) cat.Attribute("name"),
SubCatId = (int) subcat.Attribute("id"),
SubCatName = (string) subcat.Attribute("name"),
TId = (int) t.Attribute("id"),
TName = (string) t.Attribute("name"),
CutId = (int) cut.Attribute("id")
CutName = (string) cut.Attribute("name")
CutUrl = (string) cut.Attribute("cutURL")
};
Note that I've converted all the ID values to int rather than string. You could convert them to strings instead, of course, but if they are all integers, it makes sense to parse them as such.
Jon's suggestion to use LINQ to XML is the way to go, but I've included the old way below. My XPath is a little (very) rusty, so forgive me if there are any mistakes:
var doc = new XmlDocument(); //your document
var xmlnsManager = new System.Xml.XmlNamespaceManager(doc.NameTable);
xmlnsManager.AddNamespace("os", "http://bla");
foreach (XmlNode node in doc.SelectNodes("//os:subcat/os:t/os:cut", xmlnsManager))
{
string value = node.Attributes.GetNamedItem("name").Value;
}
See this article if you need more help: http://support.microsoft.com/kb/318545
Consider using XElement along with Lambda expression.
XNamespace osNs = "http://xml.com"; // Like Jon said, you haven't included the namespace url
XElement taxElement = XElement.Load("path/to/your/xml/file");
foreach(var cat in taxElement.Decendents(osNs + "cat"))
{
Console.WriteLine(cat.Attribute("id").Value);
foreach(var subcat in cat.Decendents(osNs + "subcat"))
{
Console.WriteLine(subcat.Attribute("id").Value);
foreach(var t in subcat.Decendents(osNs + "t"))
{
Console.WriteLine(t.Attribute("id").Value);
foreach(var cut in t.Decendents(osNs + "cut"))
{
Console.WriteLine(cut.Attribute("id").Value);
Console.WriteLine(cut.Attribute("name").Value);
Console.WriteLine(cut.Attribute("cutURL").Value);
}
}
}
}
It's just capturing one node at by another. If you want to get all the curURL then you can just write something like this:
foreach(var cut in taxElement.Decendents(osNs + "cut"))
{
Console.WriteLine(cut.Attribute("cutURL"));
}
Even you can use Lambda like if you want something like all os:cut where os:subcat id = 22
taxElement.Decendents("osNs + "subcat").Where(p => p.Attribute("id").Value == "22").Decendents(osNs + "cut");
Please go through some tutorial on LINQ to XML or something on XElement.
Hope this helps!

Categories