如何使这个LINQ to XML查询更优雅?

时间:2010-03-01 12:22:25

标签: c# linq-to-xml

我有一组MODS记录,如下所示:

<modsCollection>
<mods [namespaces etc] >
    <genre authority="diva" type="contentType" lang="eng">Other academic</genre>
    <genre authority="diva" type="contentType" lang="swe">Övrigt vetenskapligt</genre>
    <name type="personal">
      <namePart type="family">Svensson</namePart>
      <namePart type="given">Sven</namePart>
      <namePart type="date">1880-</namePart>
      <role>
        <roleTerm type="code" authority="marcrelator">aut</roleTerm>
      </role>
      <affiliation>Stockholms universitet, institutionen institutionen</affiliation>
    </name>
[...]
</mods>
<mods/>
<mods/>
</modsCollection>

我的LINQ查询搜索colloction以查找与某个具有某个角色的人关联的记录,如下所示:

XElement[] hits = (from record in x.Root.Elements(modsV3 + "mods").Elements(modsV3 + "name")
    from r1 in record.Elements(modsV3+"namePart")
    where  
        r1.HasAttributes && 
        r1.Attribute("type").Value == "family" &&
        r1.Value == familyName
   from r2 in record.Elements(modsV3 + "namePart")
   where
       r2.HasAttributes &&
       r2.Attribute("type").Value == "given" &&
       r2.Value == givenName
   from r3 in record.Elements(modsV3 + "role").Elements(modsV3+"roleTerm")
   where
       r3.HasAttributes &&
       r3.Attribute("type").Value == "code" &&
       r3.Value == "aut"
   select r1.Parent.Parent).ToArray<XElement>();    

我认为这个查询可以更好地编写。怎么样?

2 个答案:

答案 0 :(得分:2)

我知道您只想使用LINQ,但也许与XPath混合可以简化您的代码:

XElement[] hits = (from record in config.Elements(modsV3 + "mods").Elements(modsV3 + "name")
where   record.XPathSelectElement(string.Format("./{0}namePart[@type='family' and .='{1}']", modsV3, familyName)) != null &&
        record.XPathSelectElement(string.Format("./{0}namePart[@type='given' and .='{1}']", modsV3, givenName)) != null &&
        record.XPathSelectElement(string.Format("./{0}role/{0}roleTerm[@type='code' and .='aut']", modsV3)) != null
select record.Parent).ToArray<XElement>(); 

答案 1 :(得分:2)

我会使用Extension方法语法,并使Linq过滤器方法如下所示:

    private static XElement[] GetHits(XDocument x, string modsV3, string givenName, string familyName)
    {

        return x.Root.Elements(modsV3 + "mods")
            .MatchNamePart("given", givenName)
            .MatchNamePart("family", familyName).ToArray();
    }

    private static string modsV3 = "whatever";

    private static IEnumerable<XElement> MatchNamePart(this IEnumerable<XElement> records, string type, string givenName)
    {
        return records.Where(rec => rec.Element(modsV3 + "name").
            Elements(modsV3 + "namePart").Any(r1 => HasAttrib(r1, type, givenName)));
    }

    private static bool HasAttrib(XElement element, string attribName, string value)
    {
        return  element.HasAttributes &&
                element.Attribute("type").Value == attribName &&
                element.Value == value;
    }

这只是名称匹配。但是您可以将这些方法用作构建块。您可以在查询此类文档的任何位置重复使用名称部分匹配,因此不可重用的部分很小。查询的后半部分可以从此示例派生。