I have some XML that looks like this (highly simplified):
<?xml version="1.0"?>
<example>
<shortcuts>
<shortcut name="shortcut1">
<property name="name1" value="value1" />
<property name="name2" value="value2" />
</shortcut>
</shortcuts>
<data>
<datum name="datum1">
<property name="name1" value="value1" />
<property name="name2" value="value2" />
</datum>
<datum name="datum2">
<shortcutRef name="shortcut1" />
</datum>
<datum name="datum3">
<shortcutRef name="shortcut1" />
<property name="name3" value="value3" />
</datum>
</data>
</example>
As you can see, it is structured such that “shortcuts” can be defined which consist of one or more properties. Data can then be described explicitly with properties, or one or more shortcuts, or a mix of both (and there is no specific order).
I want to parse this with XmlReader (XmlDocument would be easier but won’t work here because the XML file is too large). I thought a good way to do this would be to store XML subtrees of each shortcut in a dictionary keyed by the shortcut names, which are unique. Then when they are referenced, I could just read through that subtree XmlReader rather than the main one. However the subtree XmlReader must still be linked to the main XmlReader because the XML that comes out is not what I expect. Here is my code:
using(XmlReader xml = XmlReader.Create("example.xml"))
{
Dictionary<string, XmlReader> shortcuts = new Dictionary<string, XmlReader>();
xml.ReadToDescendant("shortcuts");
xml.ReadToDescendant("shortcut");
do
{
shortcuts.Add(xml.GetAttribute("name"), xml.ReadSubtree());
} while(xml.ReadToNextSibling("shortcut"));
xml.ReadToFollowing("data");
while(xml.ReadToFollowing("datum"))
{
Console.WriteLine(xml.GetAttribute("name"));
XmlReader datum = xml.ReadSubtree();
while(datum.Read())
{
if(datum.Name == "property")
{
Console.WriteLine(datum.GetAttribute("name") + ':' + datum.GetAttribute("value"));
}
else if(datum.Name == "shortcutRef")
{
XmlReader shortcut_ref = shortcuts[datum.GetAttribute("name")];
while(shortcut_ref.ReadToFollowing("property"))
{
Console.WriteLine(shortcut_ref.GetAttribute("name") + ':' + shortcut_ref.GetAttribute("value"));
}
}
}
}
}
What is the best way to parse XML that is structured in this way?
It’s not entirely clear what you want to do – but since you use the words “play back” then I am guessing you don’t need to store ALL the values from the XML nodes (data / datum) in memory (you can discard them after use), however you need to cache the shortcut properties so that you can re-iterate through them when they are referenced… You just about had it, but instead of storing the XML nodes, just store the objects instead in the dictionary.
Otherwise, if that is not it, then you are trying to access serial data in a random access manner. Your best bet would be to convert/save the data into a database. Something like SQLite would do it.