2016-12-06 104 views
0

从父节点XML标记属性值。这是我的输入XML获取到最后一个子节点

<?xml version="1.0" encoding="UTF-8"?> 
<Menu TextField="Menu"> 
    <Menu TextField="Approvals"> 
     <Menu TextField="Vacation/Leave"> 
     <Menu TextField="Vacation Pre-Request Approval" /> 
     <Menu TextField="Vacation Approval" /> 
     </Menu> 
     <Menu TextField="Late Come Approval" /> 
     <Menu TextField="Loan Approval" /> 
     <Menu TextField="Department Change Approval" /> 
     <Menu TextField="Resignation/Termination"> 
     <Menu TextField="Resignation Approval" /> 
     <Menu TextField="Resignation Clearance" /> 
     </Menu> 
    </Menu> 
    <Menu TextField="Employee Transactions"> 
     <Menu TextField="Change Designation" /> 
     <Menu TextField="Organization"> 
     <Menu TextField="Organization Designation & Grade" /> 
     </Menu> 
     <Menu TextField="Change Grade" /> 
    </Menu> 
</Menu> 

我想提取TextField,形成类似下面的字符串:

Approvals > Vacation/Leave > Vacation Pre-Request Approval 
Approvals > Vacation/Leave > Vacation Approval 
Approvals > Late Come Approval 
Approvals > Loan Approval 
Approvals > Department Change Approval 
Approvals > Resignation/Termination > Resignation Approval 
Approvals > Resignation/Termination > Resignation Clearance 
Employee Transactions > Change Designation 
Employee Transactions > Organization > Organization Designation & Grade 
Employee Transactions > Change Grade 

我向将TextField的第一个标记值打印到字符串中TextField的最后一个标记值。以下是我尝试过的代码,但是打印的所有TextField值不是我需要的结构格式。

var menus = (from menu in XDocument.Parse(xml).Descendants("Menu") 
      select new 
       { 
        TextField = (string)menu.Attribute("TextField") 
       }).ToList(); 

回答

1

如果你想从你的菜单深度indipendent,你可以去递归:

IEnumerable<string> GetMenuTexts(XElement menuElement) { 
    string ownText = menuElement.Attribute("TextField").Value; 
    if (!menuElement.Elements("Menu").Any()) { 
     return new string[] { ownText }; 
    } 
    else { 
     var menus = 
      from subMenuElement in menuElement.Elements("Menu") 
      from menuText in GetMenuTexts(subMenuElement) 
      select ownText + " > " + menuText; 
     return menus; 
    } 
} 

你打电话给你的递归方法是这样的:

var menus = (from menuText in GetMenuTexts(XDocument.Parse(xml).Root) 
      select new 
       { 
        TextField = menuText 
       }).ToList(); 

如果你不想打印根菜单,你必须从根目录下的元素开始:

var menus = (from menuElement in XDocument.Parse(xml).Root.Elements("Menu") 
      from menuText in GetMenuTexts(menuElement) 
      select new 
       { 
        TextField = menuText 
       }).ToList(); 
+0

无法从'System.Collections.Generic.IEnumerable '转换为'System.Xml.Linq.XElement' –

+0

您是对的。我编辑了我的答案。 – Sefe

+0

太棒了!它也打印菜单。我不想在列表中打印。任何想法? –

1

试试这个linq xml查询。确保你将'&'替换为'& amp;'

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Xml; 
using System.Xml.Linq; 



namespace ConsoleApplication29 
{ 
    class Program 
    { 
     const string FILENAME = @"c:\temp\test.xml"; 
     static void Main(string[] args) 
     { 
      XDocument doc = XDocument.Load(FILENAME); 

      XElement menu = doc.Descendants().Where(x => (string)x.Attribute("TextField") == "Menu").FirstOrDefault(); 
      foreach (XElement element in menu.Elements()) 
      { 
       string textField = (string)element.Attribute("TextField"); 
       foreach (XElement subElement in element.Elements()) 
       { 
        List<string> textStrings = subElement.DescendantNodesAndSelf().Select(x => (string)((XElement)x).Attribute("TextField")).ToList(); 
        textStrings.Insert(0, textField); 
        Console.WriteLine(string.Join(" > ", textStrings)); 
       } 
      } 
      Console.ReadLine(); 
     } 
    } 

} 
+0

这是我见过的最美丽的答案之一。但是这样的打印答案是:Approvals> Vacation/Leave> Vacation Pre-Request Approval> Vacation Approval –

+0

但我希望像Approvals> Vacation/Leave> Vacation Pre-Request Approval Approvals> Vacation/Leave> Vacation Approval –

+0

If Sefe hasn给你的代码。我可以修改。为了获得预期的结果,我需要修改代码以使用递归方法()。 – jdweng