【问题标题】:LINQ 4 XML - What is the proper way to query deep in the tree structure?LINQ 4 XML - 在树结构中深入查询的正确方法是什么?
【发布时间】:2010-03-25 17:46:06
【问题描述】:

我有一个深度为 4 的 XML 结构:

<?xml version="1.0" encoding="utf-8"?>
<EmailRuleList xmlns:xsd="EmailRules.xsd">
  <TargetPST name="Tech Communities">
    <Parse emailAsList="true" useJustDomain="false" fromAddress="false" toAddress="true">
      <EmailRule address="@aspadvice.com" folder="Lists, ASP" saveAttachments="false" />
      <EmailRule address="@sqladvice.com" folder="Lists, SQL" saveAttachments="false" />
      <EmailRule address="@xmladvice.com" folder="Lists, XML" saveAttachments="false" />
    </Parse>
    <Parse emailAsList="false" useJustDomain="false" fromAddress="false" toAddress="true">
      <EmailRule address="northcoloradoarchitects@googlegroups.com" folder="Special Interest Groups|Northern Colorado Architects Group" saveAttachments="false" />
      <EmailRule address="spambayes@python.org" folder="Support|SpamBayes" saveAttachments="false" />
    </Parse>
    <Parse emailAsList="false" useJustDomain="false" fromAddress="true" toAddress="false">
      <EmailRule address="support@godaddy.com" folder="Support|GoDaddy" saveAttachments="false" />
      <EmailRule address="renew@no-ip.com" folder="Support|No-IP.com" saveAttachments="false" />
      <EmailRule address="discuss@orchardproject.net" folder="Discussions|Orchard Project" saveAttachments="false" />
    </Parse>
    <Parse emailAsList="false" useJustDomain="true" fromAddress="true" toAddress="false">
      <EmailRule address="@agilejournal.com"     folder="Newsletters|Agile Journal" saveAttachments="false"/>
      <EmailRule address="@axosoft.ccsend.com"   folder="Newsletters|Axosoft Newsletter" saveAttachments="false"/>
      <EmailRule address="@axosoft.com"          folder="Newsletters|Axosoft Newsletter" saveAttachments="false"/>
      <EmailRule address="@cmcrossroads.com"     folder="Newsletters|CM Crossroads" saveAttachments="false" />
      <EmailRule address="@urbancode.com"        folder="Newsletters|Urbancode" saveAttachments="false" />
      <EmailRule address="@urbancode.ccsend.com" folder="Newsletters|Urbancode" saveAttachments="false" />
      <EmailRule address="@Infragistics.com"     folder="Newsletters|Infragistics" saveAttachments="false" />
      <EmailRule address="@zdnet.online.com"     folder="Newsletters|ZDNet Tech Update Today" saveAttachments="false" />
      <EmailRule address="@sqlservercentral.com" folder="Newsletters|SQLServerCentral.com" saveAttachments="false" />
      <EmailRule address="@simple-talk.com"      folder="Newsletters|Simple-Talk Newsletter" saveAttachments="false" />
    </Parse>
  </TargetPST>
  <TargetPST name="[Sharpen the Saw]">
    <Parse emailAsList="false" useJustDomain="false" fromAddress="false" toAddress="true">
      <EmailRule address="rmiug-jobs@yahoogroups.com" folder="Head Geek|Job Alerts" saveAttachments="false" />
      <EmailRule address="inkedinusmc@yahoogroups.com" folder="Social|LinkedIn USMC" saveAttachments="false"/>
    </Parse>
    <Parse emailAsList="false" useJustDomain="false" fromAddress="true" toAddress="false">
      <EmailRule address="JobAlerts@CyberCoders.com" folder="Head Geek|Job Alerts" saveAttachments="false" />
      <EmailRule address="jobs@dice.com" folder="Head Geek|Job Alerts" saveAttachments="false" />
      <EmailRule address="news@cruisecritic.com" folder="Social|Cruise Critic" saveAttachments="false"/>
    </Parse>
    <Parse emailAsList="false" useJustDomain="true" fromAddress="true" toAddress="false">
      <EmailRule address="@moody.edu" folder="Social|5 Love Languages" saveAttachments="false" />
      <EmailRule address="@postmaster.twitter.com" folder="Social|Twitter" saveAttachments="false"/>
      <EmailRule address="@diabetes.org" folder="Physical|American Diabetes Association" saveAttachments="false"/>
      <EmailRule address="@membership.webshots.com" folder="Social|Webshots" saveAttachments="false"/>
    </Parse>
  </TargetPST>
</EmailRuleList>

现在,我有一个从传入电子邮件解析的 FromAddress 和一个 ToAddress。我想对从此 XML 反序列化的类集进行 LINQ 查询。例如: ToAddress = asp@aspadvice.com FromAddress = keithb@sol3.net

查询:

  • 获取 EmailRule.Include(Parse).Include(TargetPST) where address == ToAddress AND Parse.ToAddress==true AND Parse.useJustDomain==false
  • 获取 EmailRule.Include(Parse).Include(TargetPST) where address == [ToAddress Domain Only] AND Parse.ToAddress==true AND Parse.useJustDomain==true
  • 获取 EmailRule.Include(Parse).Include(TargetPST) where address == FromAddress AND Parse.FromAddress==true AND Parse.useJustDomain==false
  • 获取 EmailRule.Include(Parse).Include(TargetPST) where address == [FromAddress Domain Only] AND Parse.FromAddress==true AND Parse.useJustDomain==true

我很难弄清楚这个 LINQ 查询。当然,我可以像这样循环 XML 中的所有位(包括反序列化为对象):

XmlSerializer s = new XmlSerializer(typeof(EmailRuleList));
TextReader r = new StreamReader(path);
_emailRuleList = (EmailRuleList)s.Deserialize(r);

TargetPST[] PSTList = _emailRuleList.Items;
foreach (TargetPST targetPST in PSTList)
{
    olRoot = GetRootFolder(targetPST.name);
    if (olRoot != null)
    {
        Parse[] ParseList = targetPST.Items;
        foreach (Parse parseRules in ParseList)
        {
            EmailRule[] EmailRuleList = parseRules.Items;
            foreach (EmailRule targetFolders in EmailRuleList)
            {
            }
        }
    }
}

但是,这意味着要为每个地址遍历所有这些循环。对我来说查询对象更有意义。任何提示表示赞赏!

【问题讨论】:

  • 我不太确定我是否在关注 Keith。因此,您正在尝试获取每个与特定域匹配和/或列出的 EmailRule?
  • 当我收到一封电子邮件时,收件地址或发件人地址可能匹配规则(或 2 或 3)。从那里,根据 Parse 元素中的布尔设置,我可以确定它是否是正确的运行规则。我厌倦了 Outlook 无法处理基于列表的电子邮件,并且从那以后一直在慢慢扩展它。

标签: linq-to-xml linq-to-objects


【解决方案1】:

这里有这段代码:

XmlSerializer s = new XmlSerializer(typeof(EmailRuleList)); 
TextReader r = new StreamReader(path); 
_emailRuleList = (EmailRuleList)s.Deserialize(r); 

TargetPST[] PSTList = _emailRuleList.Items; 
foreach (TargetPST targetPST in PSTList) 
{ 
    olRoot = GetRootFolder(targetPST.name); 
    if (olRoot != null) 
    { 
        Parse[] ParseList = targetPST.Items; 
        foreach (Parse parseRules in ParseList) 
        { 
            EmailRule[] EmailRuleList = parseRules.Items; 
            foreach (EmailRule targetFolders in EmailRuleList) 
            { 
            } 
        } 
    } 
} 

实际上只是 LINQ 中的以下内容:

var query = from targetPST in _emailRuleList.Items
            let olRoot = GetRootFolder(targetPST.name)
            where olRoot != null
            from parseList in targetPST.Items
            from emailRule in parseList.Items
            select [whatever you want to select];

从这里,只需包含适当的 where 子句。在每个“级别”,您都可以访问之前在 from 子句中指定的对象,因此,如果您想做一个查询(您的第一个查询),它会是这样的:

where emailRule.address == ToAddress && 
    parseList.toAddress == true &&
    parseList.useJustDomain == false
select new {
    EmailRule = emailRule,
    Parse = parseList,
    TargetPST = targetPST
}

要在方法中执行此操作,我认为您弊大于利(尤其是在可读性方面),但就是这样。关于为什么如此复杂,需要注意的重要一点是,一组嵌套的 FROM 子句转换为 SelectMany,并且因为最终您需要 EmailRule 及其关联的父对象,所以您必须在一组嵌套的 lambda 中进行所有选择为了引用父对象(因为子对象本身没有反向引用)。

_emailRuleList
    .Where( targetPst => GetRootFolder( targetPst.Name ) != null )
    .SelectMany( targetPst => {
        return targetPst.Items.SelectMany( parse => {
            return parse.Items.Select( rule => {
                return new {
                    TargetPST = targetPst,
                    Parse = parse,
                    EmailRule = rule
                };
            } );
        } );
    } )
    .Where( x => x.EmailRule.address == ToAddress &&
                 x.Parse.toAddress == true &&
                 x.Parse.useJustDomain == false );

【讨论】:

  • 无论如何做类似的事情: var pRules = _emailRuleList.Items.Where(a => a.Items.Where(b => b.Items.Where(c => c.address == toAddress ))).ToList();
  • 嗯,除了更难阅读之外,是的,您可以这样做。但是你不能嵌套这样的 WHERE 方法。问题是您想要带有 Parse 和 TargetPST 的 EmailRule。您在这里得到的是所有各种条件都为真的 TargetPST。
  • 如果你想使用一组方法来构造你的查询,我认为你会为了让反向引用正常工作而为自己付出更多的时间(要做到这一点,整个事情必须是一组嵌套的 lambda,就像你正在做的那样)而如果你使用 LINQ 查询,它会为你处理。
  • 是的。发现了。还与从方法返回匿名类型作斗争。哈哈。由于变量改变但 linq 语句没有改变,我将它移到一个方法中。我需要从整个混乱中返回 2 个刺痛和一个布尔值,因此创建了一个类并删除了 var 以支持定义的类。像冠军一样工作!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多