XML / C# Loop through nodes of the same name - c#

I have this XML file with keys and values, and I currently loop through the XML doc, and I read all the data.
However, I have certain 'keys' or 'Nodes' that have the same keyname, but different (or same) values.
I need to loop through these same nodes within the same parent node.
<tile>
<x>0</x>
<y>1</y>
<name>Grass</name>
<entity>Tree</entity>
<entity>Building</entity>
<entity>Something</entity>
</tile>
<tile>
<x>1</x>
<y>2</y>
<name>Dirt</name>
<entity>Tree</entity>
<entity>Building</entity>
</tile>
I need to get X, Y and the Name, and an array/list of the entity.
This I need for every Tile in the XML.
So I need to loop through all of the and get the contents, including a list with the
Current code:
XmlElement element = doc.DocumentElement;
XmlNodeList nList = element.SelectNodes("/map/tile");
foreach(XmlNode node in nList){
int x = int.Parse(node["x"].InnerText);
int y = int.Parse(node["y"].InnerText);
String materialName = node["name"].InnerText;
for(node["entity"] in allEntityNodesWithinThisTile){ }
}
Thanks

string xml = #"<tile>
<x>0</x>
<y>1</y>
<name>Grass</name>
<entity>Tree</entity>
<entity>Building</entity>
<entity>Something</entity>
</tile>";
var data = from t in XElement.Parse(xml).DescendantsAndSelf("tile")
select new {
X=(int)t.Element("x"),
Y=(int)t.Element("y"),
Name=(string)t.Element("name"),
Entities= t.Elements("entity").Select (x => x.Value)
};

var data = from t in XElement.Load(xmlFileName).DescendantsAndSelf("tile")
select new {
X=(int)t.Element("x"),
Y=(int)t.Element("y"),
Name=(string)t.Element("name"),
Entities= t.Elements("entity").Select (x => x.Value)
};

Related

C# parsing multiple elements

I have below xml structure.
<Bd>
<Det AccNo="380619034" Zip="344000"></Det>
<Det AccNo="380619022" Zip="345000"></Det>
</Bd>
It's known that there are always 2 elements under <Bd> tag.
I am able to retrieve first element using below code;
string soapResult = rd.ReadToEnd();
var xdoc = XDocument.Parse(soapResult);
var y = xdoc.Descendants("Bd");
foreach (var x in y) {
var AccNo = x.Element("Bd")?.Element("Det")?.Attribute("AccNo")?.Value;
}
However this code is only giving me first element. I want to get the second element as well but not able to do so. What am i missing?
You can use Linq without loop, like the follwing code :
XDocument xDocument = XDocument.Parse(soapResult);
IEnumerable<string> accNoList = xDocument.Descendants("Bd")
.Descendants()
.Select(x => x.Attribute("AccNo").Value);
demo
Console.WriteLine(string.Join(", ", accNoList));
Outcome
"380619034, 380619022"
For your code, you can change it to:
var xdoc = XDocument.Parse(soapResult);
var y = xdoc.Descendants("Bd")
.Descendants();
foreach (var x in y)
{
var AccNo = x.Attribute("AccNo")?.Value;
Console.WriteLine(AccNo);
}
I hope this will help you out.

C# Read a specific element which is in a XML Node

I searched a long time in order to get an answer but as i can see is not working.
I have an XML File and I would like to read a specific element from a node.
For example, this is the XML:
<Root>
<TV>
<ID>2</ID>
<Company>Samsung</Company>
<Series>13523dffvc</Series>
<Dimesions>108</Dimesions>
<Type>LED</Type>
<SmartTV>Yes</SmartTV>
<OS>WebOS</OS>
<Price>1993</Price>
</TV>
</Root>
I want to get the ID element in the code as a variable so i can increment it for the next item which i will add.
This is the code at this moment, but i can not find a way to select something from the item itself.
XDocument doc = XDocument.Load("C:TVList.XML");
XElement TV = doc.Root;
var lastElement = TV.Elements("TV").Last()
A query for the last TV's id (this will return 0 if there are no elements):
var lastId = (int) doc.Descendants("TV")
.Elements("ID")
.LastOrDefault();
You might also want the highest id (in case they're not in order):
var maxId = doc.Descendants("TV")
.Select(x => (int)x.Element("ID"))
.DefaultIfEmpty(0)
.Max();
See this fiddle for a working demo.
Use like this to get id value
XDocument doc = XDocument.Load(#"C:\TVList.XML");
XElement root = doc.Element("Root");
XElement tv = root.Element("TV");
XElement id = tv.Element("ID");
string idvalue = id.Value;
also make your <Type>LED</Tip> tag of xml to <Type>LED</Type> for match

Extracting XML values from two nodes

I want to extract the value in the moduleId attibute and the value from the Field node. For example, in this first node I want to extract the 447 in the moduleId and the 124694 from the Field node. I have the XML loaded in an XDocument. The end result will be a Tuple where the first item is the value from the moduleId attribute and the second item is the value from the Field node. Is there a way I can do this using one XLinq statement?
As a bonus...I only want to do it for nodes where the guid = "07a188d3-3f8c-4832-8118-f3353cdd1b73". This part I can probably figure out if someone can tell me how to extract information from two nodes, but a bonus would be to add the WHERE clause in there for me :)
<Records>
<Record moduleId="447">
<Field guid="07a188d3-3f8c-4832-8118-f3353cdd1b73">124694</Field>
</Record>
<Record moduleId="447">
<Field guid="07a188d3-3f8c-4832-8118-f3353cdd1b73">124699</Field>
</Record>
<Records>
I have gotten as far as extracting the Field value using this...
IEnumerable<string> c = from p in sourceDocument.Descendants("Field")
where p.Attribute("guid").Value == "07a188d3-3f8c-4832-8118-f3353cdd1b73"
select p.Value;
But I have no idea how to get information from both the Record node and the Field node.
Give this a try:
var doc = XDocument.Parse(xml);
var r = doc.Descendants("Record")
.Where(n => n.Element("Field").Attribute("guid").Value == "07a188d3-3f8c-4832-8118-f3353cdd1b73")
.Select(n => new { ModuleId = n.Attribute("moduleId").Value, Field = n.Element("Field").Value });
var a = r.ToArray();
Here is a solution that uses LINQ Query Syntax:
XDocument document = XDocument.Parse(xml);
var query =
from el in document.Root.Elements("Record")
where (string)el.Element("Field").Attribute("guid") ==
"07a188d3-3f8c-4832-8118-f3353cdd1b73"
select new
{
ModuleId = (string)el.Attribute("moduleId"),
Field = (string)el.Element("Field")
};
foreach (var item in query)
{
Console.WriteLine
("ModuleId:[{0}]\nField:[{1}]\n--",
item.ModuleId,
item.Field);
}

A better way to handle XML updation

I have a DataGridView control where some values are popluted.
And also I have an xml file. The user can change the value in the Warning Column of DataGridView.And that needs to be saved in the xml file.
The below program just does the job
XDocument xdoc = XDocument.Load(filePath);
//match the record
foreach (var rule in xdoc.Descendants("Rule"))
{
foreach (var row in dgRulesMaster.Rows.Cast<DataGridViewRow>())
{
if (rule.Attribute("id").Value == row.Cells[0].Value.ToString())
{
rule.Attribute("action").Value = row.Cells[3].Value.ToString();
}
}
}
//save the record
xdoc.Save(filePath);
Matching the grid values with the XML document and for the matched values, updating the needed XML attribute.
Is there a better way to code this?
Thanks
You could do something like this:
var rules = dgRulesMaster.Rows.Cast<DataGridViewRow>()
.Select(x => new {
RuleId = x.Cells[0].Value.ToString(),
IsWarning = x.Cells[3].Value.ToString() });
var tuples = from n in xdoc.Descendants("Rule")
from r in rules
where n.Attribute("id").Value == r.RuleId
select new { Node = n, Rule = r };
foreach(var tuple in tuples)
tuple.Node.Attribute("action").Value = tuple.Rule.IsWarning;
This is basically the same, just a bit more LINQ-y. Whether or not this is "better" is debatable. One thing I removed is the conversion of IsWarning first to string, then to int and finally back to string. It now is converted to string once and left that way.
XPath allows you to target nodes in the xml with alot of power. Microsoft's example of using the XPathNavigator to modify an XML file is as follows:
XmlDocument document = new XmlDocument();
document.Load("contosoBooks.xml");
XPathNavigator navigator = document.CreateNavigator();
XmlNamespaceManager manager = new XmlNamespaceManager(navigator.NameTable);
manager.AddNamespace("bk", "http://www.contoso.com/books");
foreach (XPathNavigator nav in navigator.Select("//bk:price", manager))
{
if (nav.Value == "11.99")
{
nav.SetValue("12.99");
}
}
Console.WriteLine(navigator.OuterXml);
Source: http://msdn.microsoft.com/en-us/library/zx28tfx1(v=vs.80).aspx

Get certain xml node and save the value

Considering the following XML:
<Stations>
<Station>
<Code>HT</Code>
<Type>123</Type>
<Names>
<Short>H'bosch</Short>
<Middle>Den Bosch</Middle>
<Long>'s-Hertogenbosch</Long>
</Names>
<Country>NL</Country>
</Station>
</Stations>
There are multiple nodes. I need the value of each node.
I've got the XML from a webpage (http://webservices.ns.nl/ns-api-stations-v2)
Login (--) Pass (--)
Currently i take the XML as a string and parse it to a XDocument.
var xml = XDocument.Parse(xmlString);
foreach (var e in xml.Elements("Long"))
{
var stationName = e.ToString();
}
You can retrieve "Station" nodes using XPath, then get each subsequent child node using more XPath. This example isn't using Linq, which it looks like you possibly are trying to do from your question, but here it is:
XmlDocument xml = new XmlDocument();
xml.Load(xmlStream);
XmlNodeList stations = xml.SelectNodes("//Station");
foreach (XmlNode station in stations)
{
var code = station.SelectSingleNode("Code").InnerXml;
var type = station.SelectSingleNode("Type").InnerXml;
var longName = station.SelectSingleNode("Names/Long").InnerXml;
var blah = "you should get the point by now";
}
NOTE: If your xmlStream variable is a String, rather than a Stream, use xml.LoadXml(xmlStream); for line 2, instead of xml.Load(xmlStream). If this is the case, I would also encourage you to name your variable to be more accurately descriptive of the object you're working with (aka. xmlString).
This will give you all the values of "Long" for every Station element.
var xml = XDocument.Parse(xmlStream);
var longStationNames = xml.Elements("Long").Select(e => e.Value);

Categories

Resources