Reputation: 43
i tried to read nested XML with xmlnode but i got one issue
here is my xml file
<role name="admin">
<menu name="Setting">
<group name="settinggrup1"></group>
<group name="settinggrup2"></group>
<group name="settinggrup3"></group>
</menu>
<menu name="Service">
<group name="servicegrup1"></group>
<group name="servicegrup2"></group>
<group name="servicegrup3"></group>
</menu>
<menu name="Search">
<group name="serchgrup1"></group>
<group name="serchgrup2"></group>
<group name="serchgrup3"></group>
</menu>
</role>
and here is my code
var xmlDoc = new XmlDocument();
xmlDoc.Load(file);
XmlNodeList nodeList = xmlDoc.SelectNodes("//role[@name='" + "admin" + "']/menu");
var menus = new List<Menu>();
var groupName = new List<Group>();
Menu menu = new Menu();
foreach (XmlNode menuNode in nodeList)
{
menu.name = menuNode.Attributes["name"].Value;
foreach (XmlNode childNode in menuNode)
{
groupName.Add(new Group() { name = childNode.Attributes["name"].Value });
}
menus.Add(new Menu { name = menu.name, group = groupName });
}
here is my class
public class Menu
{
public string name { get; set; }
public List<Group> group { get; set; }
}
public class Group
{
public string name { set; get; }
}
And by that, i intended to display like
But what i got is this
Something wrong in my code part, i guess at the part when i added list at my nested foreach, but i've been trying for hours and still can't fix it. anyone can help me please, and also, please explain what my code did wrong.
Upvotes: 3
Views: 7635
Reputation: 519
As a fast solution:
// after
menu.name = menuNode.Attributes["name"].Value;
//please add
groupName = new List<Group>();
Upvotes: 2
Reputation: 236248
Your problem is that you are adding all groups to same instance of groups list. And then you are assigning that list with all groups inside to all menus.
Here is correct code:
var menus = new List<Menu>();
foreach (XmlNode menuNode in nodeList)
{
var groupName = new List<Group>(); // create list here
foreach (XmlNode childNode in menuNode)
groupName.Add(new Group { name = childNode.Attributes["name"].Value });
menus.Add(new Menu {
name = menuNode.Attributes["name"].Value,
group = groupName
});
}
You can use Linq to Xml:
var xdoc = XDocument.Load(file);
var menus = xdoc.Descendants("role")
.Where(r => (string)r.Attribute("name") == "admin")
.Elements("menu")
.Select(m => new Menu {
name = (string)m.Attribute("name"),
group = m.Elements("group")
.Select(g => new Group {
name = (string)g.Attribute("name")
}).ToList()
}).ToList();
Or with xpath:
var menus = xdoc.XPathSelectElements("//role[@name='admin']/menu")
.Select(m => new Menu { /* create menu as above */ })
.ToList();
BTW consider to use better naming and pascal case for public member names:
public class Menu
{
public string Name { get; set; }
public List<Group> Groups { get; set; }
}
Upvotes: 2