質問

I am writing an application that works along side word and makes a custom menu system for it.

I want the user to be able to essentially add an infinite sub menus.

I am reading in from a text file where a tab represents indenting.

Example text file:

GROUP
    MENU1
        SUBMENU11
               SUBSUBMENU111
                     SUBSUBMENU1111
        SUBMENU12
    MENU2
        SUBMENU21
                    SUBSUBMENU211 

Example XML output:

 <group id="GROUP" label="GROUP">
      <menu id="MENU1" label="MENU1" size="normal">
        <menu id="SUBMENU11" label="SUBMENU11" size="normal" >
          <menu id="SUBMENU111" label="SUBMENU111" size="normal" >
            <menu id="SUBMENU1111" label="SUBMENU1111" 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="SUBMENU211" label="SUBMENU211" size="normal" />
        </menu>
      </menu>
    </group>              

Currently to add at certain points ie at 5 tabs down:

path.Descendants(ns + "menu").ElementAt(currentMenuIndex)
                       .Descendants(ns + "menu").ElementAt(currentMenu1Index)
                           .Descendants(ns + "menu").ElementAt(currentMenu2Index)
                               .Descendants(ns + "menu").LastOrDefault()
                                   .Add(//add node info);

I am currently creating each of these descendant trees for each tab case, this makes the code bulky and if i can i would like to be able to do it programmatically for an infinite amount of tabs.

Any light you can shed on this would be wonderful, I've been going round in circles for days.

役に立ちましたか?

解決

There is a much simpler syntax to create XElement and XAttributes 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>

他のヒント

If we can store the current menu indices in an array:

object[] currentMenuIndices;
void addNodeAtNTabs(nodeInfo, currentMenuIndices) {
    currentPath = path;
    name = ns + "menu"
    foreach menuIndex in currentMenuIndices {
        currentPath = Descendants(name).ElementAt(menuIndex);
    }
    currentPath.Descendants(name).LastOrDefault().Add(nodeInfo);
}

The length of currentMenuIndices should be relative to the number of tabs the node is indented by. (Sorry if my codes seems like python)

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top