C# 递归读取XML菜单数据
在博客园注册了有4年了,很遗憾至今仍未发表过博客,趁周末有空发表第一篇博客。小生不才,在此献丑了!
最近在研究一些关于C#的一些技术,纵观之前的开发项目的经验,做系统时显示系统菜单的功能总是喜欢把数据写在数据库表,然后直接读取加载到菜单树上显示。
现在想把菜单数据都放在XML里,然后递归读取XML。
由于项目使用WCF,实体类使用了两个,一个是业务逻辑层中的实体,一个是调用业务逻辑层递归方法后进行数据实体的转换,XML读取方法写在业务逻辑层中。
思路:1.先读取XML里所有的菜单 2.根据用户的权限显示所属用户的菜单加载到页面上
XML数据如下:
1 <?xml version="1.0" encoding="utf-8"?> 2 <ZCSoft.Net xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 3 <Applications> 4 <Application ID ="OA" Text="OA管理系统"> 5 <Modules> 6 <Module ID="OA_System" Text="系统管理"> 7 <Menus> 8 <Menu ID="OA_System_UserManager" Text="人员管理" URL="System/UserManager/UserManagerList.aspx"> </Menu> 9 <Menu ID="OA_System_RoleManager" Text="角色管理" URL="System/RoleManager/RoleManagerList.aspx"></Menu> 10 <Menu ID="OA_System_LoginLog" Text="登录日志" URL="System/Log/LoginLogList.aspx"></Menu> 11 <Menu ID="OA_System_OperateLog" Text="操作日志" URL="System/Log/OperateLogList.aspx"></Menu> 12 </Menus> 13 </Module> 14 15 <Module ID="OA_TargetManage" Text="目标管理"> 16 <Menus> 17 <Menu ID="OA_TargetManage_TargetSetup" Text="目标设定" URL="OA/TargetManage/TargetSetupList.aspx"> 18 </Menu> 19 </Menus> 20 </Module> 21 </Modules> 22 </Application> 23 </ZCSoft.Net>
菜单的业务逻辑实体类:
1 public class MenuTreeSearchModel 2 { 3 //菜单ID 4 public string ItemCode { get; set; } 5 6 //菜单名称 7 public string ItemName { get; set; } 8 9 //菜单显示类型 10 public string ItemType { get; set; } 11 12 //排序 13 public int ItemOrder { get; set; } 14 15 //是否显示 16 public bool Visible { get; set; } 17 18 //菜单链接 19 public string ItemUrl { get; set; } 20 21 //上级ID 22 public string ParentItem { get; set; } 23 24 //系统平台ID 25 public string ApplicationCode { get; set; } 26 27 //系统平台名称 28 public string ApplicationName { get; set; } 29 30 //模块ID 31 public string ModuleCode { get; set; } 32 33 //模块名称 34 public string ModuleName { get; set; } 35 }
递归方法,读取每个模块和模块下的菜单:
1 protected void GetChildMenuList(XElement root, List<MenuTreeSearchModel> menuTreeList) 2 { 3 var firstNode = root.FirstNode as XElement;//读取root节点内的第一个节点 4 if (null != firstNode) 5 { 6 //读取root节点下面同级的所有节点 7 var appList = 8 from ele in root.Element(firstNode.Name.LocalName).Elements() 9 select ele; 10 11 bool thisVisible = true;//默认节点是可见的 12 XAttribute thisAttr = root.Attribute("Display"); 13 if (null != thisAttr)//如果菜单的上级模块有显示属性 14 { 15 string thisDisplay = thisAttr.Value; 16 thisVisible = thisDisplay.ToLower() == "false" ? false : true; 17 } 18 19 foreach (var application in appList) 20 { 21 //模块Display属性 22 XAttribute modAttr = application.Attribute("Display"); 23 bool visible = true; 24 if (null != modAttr) 25 { 26 string display = application.Attribute("Display").Value; 27 visible = display.ToLower() == "false" ? false : true; 28 } 29 var nextNode = application.FirstNode as XElement;//该节点的下级节点 30 31 string itemType = "Folder";//目录还是菜单 32 string itemUrl = null;//链接地址 33 string parentItem = null;//上一节点ID 34 string applicationCode = null;//平台编码 35 string applicationName = null;//平台名称 36 string moduleCode = null;//模块编码 37 string moduleName = null;//模块名称 38 39 if (application.Name.LocalName == "Application") 40 { 41 applicationCode = application.Attribute("ID").Value; 42 applicationName = application.Attribute("Text").Value; 43 } 44 45 if (application.Name.LocalName == "Module") 46 { 47 moduleCode = application.Attribute("ID").Value; 48 moduleName = application.Attribute("Text").Value; 49 applicationCode = root.Attribute("ID").Value; 50 applicationName = root.Attribute("Text").Value; 51 52 if (thisVisible) //如果该模块的所属平台中的Display属性设置为可见true(注意:没有设置则默认为可见),则模块的上级为Application的ID 53 { 54 parentItem = root.Attribute("ID").Value; 55 } 56 } 57 58 if (application.Name.LocalName == "Menu") 59 { 60 itemType = "Menu"; 61 itemUrl = application.Attribute("URL").Value; 62 moduleCode = root.Attribute("ID").Value; 63 moduleName = root.Attribute("Text").Value; 64 applicationCode = root.Parent.Parent.Attribute("ID").Value; 65 applicationName = root.Parent.Parent.Attribute("Text").Value; 66 67 if (thisVisible) //如果该菜单的所属模块中的Display属性设置为可见true(注意:没有设置则默认为可见),则菜单的上级为Module的ID 68 { 69 parentItem = root.Attribute("ID").Value; 70 } 71 else//如果该菜单的所属模块中的Display属性设置为不可见false,则菜单的上级为Application的ID 72 { 73 parentItem = root.Parent.Parent.Attribute("ID").Value; 74 } 75 } 76 77 MenuTreeSearchModel model = new MenuTreeSearchModel(); 78 model.ItemCode = application.Attribute("ID").Value; 79 model.ItemName = application.Attribute("Text").Value; 80 model.ItemType = itemType; 81 model.ItemOrder = 0; 82 model.Visible = visible; 83 model.ItemUrl = itemUrl; 84 model.ParentItem = parentItem; 85 model.ApplicationCode = applicationCode; 86 model.ApplicationName = applicationName; 87 model.ModuleCode = moduleCode; 88 model.ModuleName = moduleName; 89 menuTreeList.Add(model); 90 91 if (null != nextNode)//如果还有下级节点 92 { 93 //调用递归 94 GetChildMenuList(application, menuTreeList); 95 } 96 } 97 } 98 }
从XML文档读取:
1 /// <summary> 2 /// 从XML文件读取菜单节点 3 /// </summary> 4 /// <returns></returns> 5 public List<MenuTreeSearchModel> GetMenuTreeByReadXML() 6 { 7 List<MenuTreeSearchModel> list = new List<MenuTreeSearchModel>(); 8 //读取XML文档路径,这里我把XML放在网站的bin目录里 9 string xmlPath = AppDomain.CurrentDomain.BaseDirectory + "Foundation.xml"; 10 XElement root = XElement.Load(xmlPath); 11 var appList = 12 from ele in root.Element("Applications").Elements() 13 select ele; 14 //按系统平台筛选 15 foreach (var application in appList) 16 { 17 MenuTreeSearchModel model = new MenuTreeSearchModel(); 18 model.ItemCode = application.Attribute("ID").Value; 19 model.ItemName = application.Attribute("Text").Value; 20 model.ItemType = "Folder"; 21 model.ItemOrder = 0; 22 model.Visible = true; 23 model.ItemUrl = null; 24 model.ParentItem = null; 25 model.ApplicationCode = application.Attribute("ID").Value; 26 model.ApplicationName = application.Attribute("Text").Value; 27 model.ModuleCode = null; 28 model.ModuleName = null; 29 list.Add(model); 30 31 //递归调用 32 GetChildMenuList(application, list); 33 34 } 35 36 return list; 37 }
以下是在调用服务契约方法时进行的实体类:
1 public class PublicUserMenuTreeData 2 { 3 //菜单ID 4 public string ItemCode { get; set; } 5 6 //菜单名称 7 public string ItemName { get; set; } 8 9 //菜单显示类型 10 public string ItemType { get; set; } 11 12 //排序 13 public int ItemOrder { get; set; } 14 15 //是否显示 16 public bool Visible { get; set; } 17 18 //菜单链接 19 public string ItemUrl { get; set; } 20 21 //上级ID 22 public string ParentItem { get; set; } 23 24 //系统平台ID 25 public string ApplicationCode { get; set; } 26 27 //系统平台名称 28 public string ApplicationName { get; set; } 29 30 //模块ID 31 public string ModuleCode { get; set; } 32 33 //模块名称 34 public string ModuleName { get; set; } 35 //当前菜单下的菜单集合 36 public List<PublicUserMenuTreeData> UserMenuTreeDatas { set; get; } 37 }
实体转换方法:
1 public PublicUserMenuTreeData TransferUserMenuTreeToPublicUserMenu(MenuTreeData userMenuTreeData) 2 { 3 PublicUserMenuTreeData pubUserMenuTreeData = new PublicUserMenuTreeData(); 4 pubUserMenuTreeData.ItemCode = userMenuTreeData.ItemCode; 5 pubUserMenuTreeData.ItemName = userMenuTreeData.ItemName; 6 pubUserMenuTreeData.ItemType = userMenuTreeData.ItemType; 7 pubUserMenuTreeData.ItemOrder = userMenuTreeData.ItemOrder; 8 pubUserMenuTreeData.Visible = userMenuTreeData.Visible; 9 pubUserMenuTreeData.ItemUrl = userMenuTreeData.ItemUrl; 10 pubUserMenuTreeData.ParentItem = userMenuTreeData.ParentItem; 11 pubUserMenuTreeData.ApplicationCode = userMenuTreeData.ApplicationCode; 12 pubUserMenuTreeData.ApplicationName = userMenuTreeData.ApplicationName; 13 pubUserMenuTreeData.ModuleCode = userMenuTreeData.ModuleCode; 14 pubUserMenuTreeData.ModuleName = userMenuTreeData.ModuleName; 15 return pubUserMenuTreeData; 16 }
用户权限菜单方法:
1 /// <summary> 2 /// 有用户权限树获取共用的用户菜单列表 3 /// </summary> 4 /// <param name="listAllUserMenu"></param> 5 /// <returns></returns> 6 public List<PublicUserMenuTreeData> GetPublicUserMenuFromUserMenuTreeData(List<MenuTreeData> listAllUserMenu) 7 { 8 List<PublicUserMenuTreeData> listPublicUserMenuTreeData = new List<PublicUserMenuTreeData>(); 9 List<MenuTreeData> list = listAllUserMenu.FindAll(d => string.IsNullOrEmpty(d.ParentItem)).ToList(); 10 foreach (var userMenuTreeData in list) 11 { 12 PublicUserMenuTreeData pubUserMenuTreeData = TransferUserMenuTreeToPublicUserMenu(userMenuTreeData); 13 pubUserMenuTreeData.UserMenuTreeDatas = GetChildData(pubUserMenuTreeData.ItemCode, listAllUserMenu); 14 listPublicUserMenuTreeData.Add(pubUserMenuTreeData); 15 } 16 return listPublicUserMenuTreeData; 17 } 18 public List<PublicUserMenuTreeData> GetChildData(string parentId, List<MenuTreeData> listUserMenuTreeData) 19 { 20 21 List<MenuTreeData> list = listUserMenuTreeData.FindAll(d => d.ParentItem == parentId).ToList(); 22 if (list.Count > 0) 23 { 24 List<PublicUserMenuTreeData> listPublicUserMenuTreeData = new List<PublicUserMenuTreeData>(); 25 foreach (var userMenuTreeData in list) 26 { 27 PublicUserMenuTreeData pubUserMenuTreeData = TransferUserMenuTreeToPublicUserMenu(userMenuTreeData); 28 pubUserMenuTreeData.UserMenuTreeDatas = GetChildData(pubUserMenuTreeData.ItemCode, listUserMenuTreeData); 29 listPublicUserMenuTreeData.Add(pubUserMenuTreeData); 30 } 31 return listPublicUserMenuTreeData; 32 } 33 return null; 34 }
系统菜单类:
1 /// <summary> 2 /// 系统菜单 3 /// </summary> 4 [DataContract()] 5 public class MenuTreeData 6 { 7 8 [DataMember()] 9 public string ItemCode { get; set; } 10 11 [DataMember()] 12 public string ItemName { get; set; } 13 14 [DataMember()] 15 public string ItemType { get; set; } 16 17 [DataMember()] 18 public int ItemOrder { get; set; } 19 20 [DataMember()] 21 public bool Visible { get; set; } 22 23 [DataMember()] 24 public string ItemUrl { get; set; } 25 26 [DataMember()] 27 public string ParentItem { get; set; } 28 29 [DataMember()] 30 public string ApplicationCode { get; set; } 31 32 [DataMember()] 33 public string ApplicationName { get; set; } 34 35 [DataMember()] 36 public string ModuleCode { get; set; } 37 38 [DataMember()] 39 public string ModuleName { get; set; } 40 41 }
后台页面加载Load代码:
1 string menuData = string.Empty; 2 3 var treeList= GetMenuTreeList(); 4 if (treeList!= null) 5 { 6 List<MenuTreeData> listAllUserMenu = treeList.FindAll(d => d.Visible).OrderBy(d => d.ItemOrder).ToList(); 7 List<PublicUserMenuTreeData> listPublicUserMenuTreeData = GetPublicUserMenuFromUserMenuTreeData(listAllUserMenu); 8 menuData = JsonConvert.SerializeObject(listPublicUserMenuTreeData); 9 }
页面加载脚本,这里使用Jquery:
1 var obj = menuData; 2 GetMenuInfo(obj); 3 function GetMenuInfo(obj) { 4 var str = ""; 5 6 var objInfo = ""; 7 if (obj) { 8 objInfo = obj.split("|"); 9 if (objInfo[0] != "") { 10 var PublicUserMenuTreeData = JSON.parse(objInfo[0]); 11 for (var i = 0; i < PublicUserMenuTreeData.length; i++) { 12 str += ("<li>"); 13 var tempmenu= PublicUserMenuTreeData[i]; 14 if (tempmenu.ItemType && tempmenu.ItemType == "Menu") { 15 str += ("<a href='#' onclick='" + tempmenu.ItemCode + "()' id='" + tempmenu.ItemCode + "'>" + tempmenu.ItemName + "</a>"); 16 str += ("<script> function " + tempmenu.ItemCode); 17 str += ("() { tabframe1.newTab({ title: '" + tempmenu.ItemName + "',"); 18 if (tempmenu.ItemUrl.indexOf('?') != -1) { 19 str += ("src: '" + tempmenu.ItemUrl + "&applicationid=" + tempmenu.ApplicationCode + "&moduleid=" + tempmenu.ModuleCode + "',"); 20 } else { 21 str += ("src: '" + tempmenu.ItemUrl + "?applicationid=" + tempmenu.ApplicationCode + "&moduleid=" + tempmenu.ModuleCode + "',"); 22 } 23 24 str += (" id: 'oa-system-" + tempmenu.ItemCode + "',"); 25 str += (" closable: true }); jQuery('#mainmenulist').hide(); return false; }<\/script>"); 26 } else { 27 str += ("<a href='#' id='" + PublicUserMenuTreeData[i].ItemCode + "'>" + PublicUserMenuTreeData[i].ItemName + "</a>"); 28 } 29 30 if (PublicUserMenuTreeData[i].UserMenuTreeDatas) { 31 str += GetRecurrenceData(PublicUserMenuTreeData[i].UserMenuTreeDatas); 32 } 33 34 str += (" </li>"); 35 } 36 37 38 } 39 } 40 41 function GetRecurrenceData(listPublicUserMenuTreeData) { 42 var str = ""; 43 if (listPublicUserMenuTreeData && listPublicUserMenuTreeData.length>0) { 44 str += (" <ul>"); 45 for (var j = 0; j < listPublicUserMenuTreeData.length; j++) { 46 str += ("<li class='divFontWeight'>"); 47 if (listPublicUserMenuTreeData[j].ItemType && listPublicUserMenuTreeData[j].ItemType == "Menu") { 48 str += ("<a href='#' onclick='" + listPublicUserMenuTreeData[j].ItemCode + "()' id='" + listPublicUserMenuTreeData[j].ItemCode + "'>" + listPublicUserMenuTreeData[j].ItemName + "</a>"); 49 str += ("<script> function " + listPublicUserMenuTreeData[j].ItemCode); 50 str += ("() { tabframe1.newTab({ title: '" + listPublicUserMenuTreeData[j].ItemName + "',"); 51 if (listPublicUserMenuTreeData[j].ItemUrl.indexOf('?') != -1) { 52 str += ("src: '" + listPublicUserMenuTreeData[j].ItemUrl + "&applicationid=" + listPublicUserMenuTreeData[j].ApplicationCode + "&moduleid=" + listPublicUserMenuTreeData[j].ModuleCode + "',"); 53 } else { 54 str += ("src: '" + listPublicUserMenuTreeData[j].ItemUrl + "?applicationid=" + listPublicUserMenuTreeData[j].ApplicationCode + "&moduleid=" + listPublicUserMenuTreeData[j].ModuleCode + "',"); 55 } 56 57 str += (" id: 'oa-system-" + listPublicUserMenuTreeData[j].ItemCode + "',"); 58 str += (" closable: true }); jQuery('#mainmenulist').hide(); return false; }<\/script>"); 59 } else { 60 str += ("<a href='#' id='" + listPublicUserMenuTreeData[j].ItemCode + "'>" + listPublicUserMenuTreeData[j].ItemName + "</a>"); 61 } 62 63 64 var ListMenuDatas = listPublicUserMenuTreeData[j].UserMenuTreeDatas; 65 str += GetRecurrenceData(ListMenuDatas); 66 67 str += ("</li>"); 68 } 69 str += (" </ul>"); 70 } 71 return str; 72 }
效果图:
这里补充一下:菜单中如果在模块Module里设置属性Display="false",则模块不显示出来,可是模块下的菜单可显示出来。
itemType=“Folder”显示类型是目录,itemType=“Menu”显示类型是菜单