I am trying to convert an XML data into dictionary. I am having problems with identical node names. C# .Net 3.5
Sample XML = the problem is I have no control over this.
How about using DynamicXml here
dynamic root = DynamicXml.Load("a.xml");
Console.WriteLine(root.a1);
foreach (var p in root.Parameter)
{
Console.WriteLine("{0}:{1}",p.ParameterName, p.ParameterValue);
}
Console.WriteLine(root.Parameter[0].ParameterValue);
EDIT
A generic approach would be to get a dictionary Dictionary<string,object>
But there are some problems while converting an xml to dictionary. For example
<a1>val1</a1>
dict["a1"]
would return val1, but what would this xml return
<a1 name="valAttr"><name>valName</name><a1>
dict["a1"]["name"]
? valAttr or valName?
And considering your example, the only difference between dict["a1"]
and dict["Parameter"]
is that
Parameter exists more than once under the same parent and it should be thought as an array rather than a
single element.
DynamicXml tries to solve these issues. Of course there is a lot of room for improvement but It should work for basic needs.
Here is a method which will distill the data into tuples and then output a dictionary. Note it doesn't check for duplicate keys, but that could be added:
string data = @"<?xml version=""1.0"" encoding=""utf-8""?>
<Root>
<a1>val1</a1>
<a2>val2</a2>
<Parameter>
<ParameterName>param1</ParameterName>
<ParameterValue>paramval1</ParameterValue>
</Parameter>
<Parameter>
<ParameterName>param2</ParameterName>
<ParameterValue>paramval2</ParameterValue>
</Parameter>
</Root>";
var elements = XDocument.Parse( data )
.Element("Root")
.Descendants();
var asTupleChildren = elements.Where (e => e.HasElements)
.Select (e => new Tuple<string,string>(e.Element("ParameterName").Value, e.Element("ParameterValue").Value ));
var asTupleElements = elements.Where (e => e.HasElements == false)
.Where (e => e.Name != "ParameterName" && e.Name != "ParameterValue" )
.Select (e => new Tuple<string,string>(e.Name.ToString(), e.Value ));
var asDictionary = asTupleElements.Concat(asTupleChildren)
.ToDictionary (te => te.Item1, te => te.Item2);
/* asDictionary is a Dictionary<String,String> (4 items)
a1 val1
a2 val2
param1 paramval1
param2 paramval2
*/
just made this, works for me. bit clunky. use it as a template.
public static Dictionary<string, dynamic> RecDis(string ThisXML)
{
Dictionary<string, dynamic> ThisBlock = new Dictionary<string, dynamic>();
XElement doc = XElement.Parse(ThisXML);
XNode[] ThisNoideArray = doc.Nodes().ToArray();
foreach (XNode park in ThisNoideArray)
{
XElement parker = XElement.Parse(park.ToString());
if (parker.HasElements)
{
ThisBlock.Add(parker.Name.ToString(), RecDis(parker.ToString()));
}
else
{
ThisBlock.Add(parker.Name.ToString(), parker.Value.ToString());
}
}
return ThisBlock;
}
Unless you provide a unique, non-nullable key, you won't be able to import to a dictionary structure. A couple of options I can think of: