【问题标题】:How to use linq to find a sub element in a list / IEnumerable?如何使用 linq 在列表/IEnumerable 中查找子元素?
【发布时间】:2013-03-28 18:07:01
【问题描述】:

我有一个 XML 结构,我将其解析并作为 IEnumerable 返回:

 <menuItem Id="1">
      <menuItem Id="2">
            <menuItem Id="5">
                  <menuItem Id="9">
                       <criterion></criterion>
                  </menuItem>
             </menuItem>
       </menuItem>
  </menuItem>
  <menuItem Id="10>
    /// huge xml document from here on...

我使用这个类来解析它:

 public static  class XmlConverter
{

    public static IEnumerable<MenuItem> Parser()
    {
        using (var fileStream = new FileStream(HttpContext.Current.Server.MapPath("~/DataSource/MenuNavigation.xml"), FileMode.Open))
        {
            return Read(fileStream);
        }
    }

    private static IEnumerable<MenuItem> Read(Stream stream)
    {
        return (IEnumerable<MenuItem>)XmlSerializer().Deserialize(stream); ;
    }


    private static XmlSerializer XmlSerializer()
    {
        return new XmlSerializer(typeof(List<MenuItem>), GetXmlRootAttribute());

    }

    private static XmlRootAttribute GetXmlRootAttribute()
    {
        return new XmlRootAttribute() { ElementName = "Navigation", IsNullable = true };
    }
}

解析成这个对象:

  public class MenuItem
{
    [XmlAttribute("Id")]
    public int Id { get; set; }
    [XmlAttribute("Name")]
    public string Name { get; set; }
    [XmlAttribute("Description")]
    public string Description { get; set; }
    [XmlAttribute("Link")]
    public string Link { get; set; }
    [XmlAttribute("Role")]
    public string RoleId { get; set; }
    [XmlAttribute("Alert")]
    public string Alert { get; set; }
    [XmlElement("Criterion")]
    public List<Criterion> Criteria { get; set; }

    private List<MenuItem> _menuItems = new List<MenuItem>();

    [XmlElement("MenuItem")]
    public MenuItem[] MenuItems
    {
        get { return _menuItems.ToArray(); }
        set
        {
            _menuItems.Clear();
            if (value != null)
            {
                _menuItems.AddRange(value);
            }
        }
    }
}

当我对返回的 IEnumerable 执行 Linq 查询时,我使用:

 var criteria = menuItems.Where(x => x.Id == menuItem.Id)
                         .Select(x => x.Criteria)
                         .FirstOrDefault();

问题是这里的 IEnumerable 只有 14 项。那些父项,所以如果我正在寻找 Id == 9 则找不到它,因为它是 Id 1 的子元素。

如何编辑上面的 linq 语句,以便它使用名为 menuItem 的元素检查每个级别,而不仅仅是相关 Id 的父级?

更新:

IEnumerable 看起来像这样:

  Count=14
 +MenuItem //nested menuItem
  Name

【问题讨论】:

  • 你是怎么解析的?包含代码。
  • 您的 MenuItem 类是什么样的?它如何代表它的孩子? (你真的有一个 4 级深的菜单结构吗?)
  • 不幸的是,我的客户要求在某些地方深度为 6。现在发布我的 MenuItem 课程
  • 究竟哪些项目在从XmlConverter.Parser() 返回的IEnumerable&lt;MenuItem&gt; 中?嵌套项是否存在?
  • 是的,它们存在并且它们嵌套在里面我将发布 IEnumerable 的样子

标签: linq linq-to-xml


【解决方案1】:

您可以先flatten 层次结构(linq 本身对此没有任何支持)-然后做您正在做的事情。

例如How do I select recursive nested entities using LINQ to Entity

...然后

var item = menuItems.Flatten(y => y.MenuItems).Where(x => x.Id == 5)
    .FirstOrDefault();

【讨论】:

  • 我会调查的。我真的希望 Linq 有一些内置的魔法
  • 我不这么认为 - 你不会失去太多 - 它会枚举 - 直到找到一个 - 唯一的问题可能是你想要的顺序,深度优先等你可以调整一下,我猜。
  • 由于我使用的是 Xml 并且文档不是一百万行长,因此无论以何种方式在列表中移动都会很快。我主要要根据他的例子让代码工作
  • 你不应该有太多的菜单项:) - 是的。由于您正在处理对象的 linq,因此您可以执行此类操作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-07
相关资源
最近更新 更多