There is a much simpler syntax to create XElement
and XAttribute
s in an Xml Document
new XElement("group",
new XAttribute("id", "GROUP"),
new XElement("menu",
new XAttribute("id", "MENU1"),
... etc
Edit How about a recursive strategy here, with some Linq:
const string menu = // I've hardcoded tabs and newlines as SO formats these out.
"GROUP\r\n" +
"MENU1\r\n" +
"\tSUBMENU11\r\n" +
"\t\tSUBSUBMENU111\r\n"+
"\t\t\tSUBSUBMENU1111\r\n" +
"\tSUBMENU12\r\n"+
"MENU2\r\n" +
"\tSUBMENU21\r\n"+
"\t\tSUBSUBMENU211";
var sr = new StringReader(menu); // Obviously use a TextReader
var lines = sr.ReadToEnd()
.Split(new[] { Environment.NewLine },
StringSplitOptions.RemoveEmptyEntries);
var indentedLines =
lines
.Skip(1) // Group isn't part of the menu
.Select(
_ => new Tuple<string, int>( // Remove whitespace
Regex.Replace(_, @"\s+", ""),
_.Split(new[] { '\t' }).Count())) // Count the tabs
.ToList();
var doc = new XDocument();
doc.Add(new XElement("group", // Add the root group
new XAttribute("id", lines[0].Trim()),
new XAttribute("label", lines[0].Trim()),
BuildTree(indentedLines, 1, String.Empty))); // Add the top lvl nodes
With this recursive helper:
IEnumerable<XElement> BuildTree(
IList<Tuple<string, int>> indentedLines,
int indentLevel, String parentNode)
{
Func<string, string> getNodeParent =
node =>
{
var line = indentedLines.First(_ => _.Item1 == node);
for (var index = indentedLines.IndexOf(line); index >= 0; index --)
{
if (indentedLines[index].Item2 < line.Item2)
{
return indentedLines[index].Item1;
}
}
return String.Empty; // has no parent
};
foreach (var line in indentedLines.Where(_ => _.Item2 == indentLevel
&& getNodeParent(_.Item1) == parentNode))
{
yield return new XElement("menu",
new XAttribute("id", line.Item1),
new XAttribute("label", line.Item1),
new XAttribute("size", "normal"),
BuildTree(indentedLines, indentLevel + 1, line.Item1));
}
}
Produces this Xml, which I think is what you are after:
<group id="GROUP" label="GROUP">
<menu id="MENU1" label="MENU1" size="normal">
<menu id="SUBMENU11" label="SUBMENU11" size="normal">
<menu id="SUBSUBMENU111" label="SUBSUBMENU111" size="normal">
<menu id="SUBSUBMENU1111" label="SUBSUBMENU1111" size="normal" />
</menu>
</menu>
<menu id="SUBMENU12" label="SUBMENU12" size="normal" />
</menu>
<menu id="MENU2" label="MENU2" size="normal">
<menu id="SUBMENU21" label="SUBMENU21" size="normal">
<menu id="SUBSUBMENU211" label="SUBSUBMENU211" size="normal" />
</menu>
</menu>
</group>