I have a xml file and I have to store the values in the list to use it later.
The xml file contain mostly ints and string
s and it looks like this:
<AllThings>
<Anythings>
<Anything Step="1" Name="1">
<Somethings>
<Something Id="10">
<Things>
<Thing Id="11">abc</Thing>
<Thing Id="12">123</Thing>
</Things>
</Something>
<Something Id="20">
<Things>
<Thing Id="21">cde</Thing>
<Thing Id="22">345</Thing>
</Things>
</Something>
<Something Id="30">
<Things>
<Thing Id="31">efg</Thing>
<Thing Id="32">567</Thing>
</Things>
</Something>
<Something Id="40">
<Things>
<Thing Id="41">ghi</Thing>
<Thing Id="42">789</Thing>
</Things>
</Something>
</Somethings>
</Anything>
<Anything Step="2" Name="2">
<Somethings>
<Something Id="10">
<Things>
<Thing Id="11">aaa</Thing>
<Thing Id="12">111</Thing>
</Things>
</Something>
<Something Id="20">
<Things>
<Thing Id="21">ccc</Thing>
<Thing Id="22">333</Thing>
</Things>
</Something>
<Something Id="30">
<Things>
<Thing Id="31">eee</Thing>
<Thing Id="32">555</Thing>
</Things>
</Something>
<Something Id="40">
<Things>
<Thing Id="41">ggg</Thing>
<Thing Id="42">777</Thing>
</Things>
</Something>
</Somethings>
</Anything>
</Anythings>
</AllThings>
What is the best way to get the values from this kind of xml and store it in the list(s)?
I've tried with using System.Xml;
to create a reader and make reader.ReadToFollowing("Something")
in combination with reader.GetAttribute("Id")
, but it hasn`t gone deep enough.
In most tutorials the xml is like:
<Animal type="cat">
<Name>Bob</Name>
<Age>8</Age>
</Animal>
and there it works
CodePudding user response:
i think you miss iterating through recursively with
.ChildNodes.OfType<XmlNode>().
CodePudding user response:
The simplest way to do this is to use XmlSerialization
. To do this, you will need to create a nested class structure matching your xml. There are plenty of utilities that will do this automatically (if you search for convert xml to c# class), but I always feel, it helps to know how to construct this yourself.
I always begin with the outer shell, and work my way inwards. So I take the root element first. AllThings has just one element AnyThings, so this class is easy to create (you will need using System.Xml.Serialization;
):
[XmlRoot]
public class AllThings
{
[XmlElement]
public Anythings Anythings { get; set; }
}
Next we look at Anythings. This holds a bunch of elements Anything, so we create the next class accordingly:
public class Anythings
{
[XmlElement]
public List<Anything> Anything { get; set; }
}
Only one thing extra to note here: the bunch of Anything is being represented as a List<Anything>
.
We move down again:
public class Anything
{
[XmlElement]
public Somethings Somethings { get; set; }
[XmlAttribute]
public int Step { get; set; }
[XmlAttribute]
public string Name { get; set; }
}
Here there is a little more of interest: as well as an XmlElement, we have two XmlAttributes. In your case the attribute Name could easily be an int
, given the values in your xml, but in my view an attribute called Name is crying out to be a string!
And going on down:
public class Somethings
{
[XmlElement]
public List<Something> Something { get; set; }
}
public class Something
{
[XmlElement]
public Things Things { get; set; }
[XmlAttribute]
public int Id { get; set; }
}
public class Things
{
[XmlElement]
public List<Thing> Thing { get; set; }
}
These are all constructed in the same way as previously, leaving only one more class:
public class Thing
{
[XmlAttribute]
public int Id { get; set; }
[XmlText]
public string Text { get; set; }
}
This (at last) adds something new, a basic XmlText element which represents the value of the node.
Having set up your classes, all that remains is to call the inbuilt deserializer, like this:
var xml = "<AllThings><Anythings><Anything Step=\"1\" Name=\"1\"><Somethings><Something Id=\"10\"><Things><Thing Id=\"11\">abc</Thing><Thing Id=\"12\">123</Thing></Things></Something><Something Id=\"20\"><Things><Thing Id=\"21\">cde</Thing><Thing Id=\"22\">345</Thing></Things></Something><Something Id=\"30\"><Things><Thing Id=\"31\">efg</Thing><Thing Id=\"32\">567</Thing></Things></Something><Something Id=\"40\"><Things><Thing Id=\"41\">ghi</Thing><Thing Id=\"42\">789</Thing></Things></Something></Somethings></Anything><Anything Step=\"2\" Name=\"2\"><Somethings><Something Id=\"10\"><Things><Thing Id=\"11\">aaa</Thing><Thing Id=\"12\">111</Thing></Things></Something><Something Id=\"20\"><Things><Thing Id=\"21\">ccc</Thing><Thing Id=\"22\">333</Thing></Things></Something><Something Id=\"30\"><Things><Thing Id=\"31\">eee</Thing><Thing Id=\"32\">555</Thing></Things></Something><Something Id=\"40\"><Things><Thing Id=\"41\">ggg</Thing><Thing Id=\"42\">777</Thing></Things></Something></Somethings></Anything></Anythings></AllThings>";
var serializer = new XmlSerializer(typeof(AllThings));
using (var reader = new StringReader(xml))
{
var allThings = (AllThings)serializer.Deserialize(reader);
//do something with allThings;
}
If you use the debugger to examine allThings, you will find that it is a c# object, with a structure exactly matching your xml. This means that you can access its values with syntax such as:
var test = allThings.Anythings.Anything[0].Somethings.Something[0].Things.Thing[0].Text;
CodePudding user response:
The following code is tested and works
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication51
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(FILENAME);
XmlSerializer serializer = new XmlSerializer(typeof(AllThings));
AllThings allthings = (AllThings)serializer.Deserialize(reader);
}
}
public class AllThings
{
[XmlArray("Anythings")]
[XmlArrayItem("Anything")]
public List<AnyThing> anythings { get;set;}
}
public class AnyThing
{
[XmlAttribute()]
public int Step { get;set;}
[XmlAttribute()]
public int Name { get; set; }
[XmlArray("Somethings")]
[XmlArrayItem("Something")]
public List<Something> somethings { get; set; }
}
public class Something
{
[XmlAttribute()]
public int Id { get; set; }
[XmlArray("Things")]
[XmlArrayItem("Thing")]
public List<Thing> things { get;set;}
}
public class Thing
{
[XmlAttribute()]
public int Id { get; set; }
[XmlText]
public string value { get; set; }
}
}