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

发布于 2024-08-23 12:00:59 字数 1637 浏览 7 评论 0原文

我有一个 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 查询用于在集合中搜索与具有特定角色的特定人员相关联的记录,如下所示:

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>();    

我认为这个查询可以写得更好。如何?

I have a collection of MODS records that looks like this:

<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>

My LINQ query to search the colloction for records affiliated with a certain person with a certain role looks like this:

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>();    

I think this query could be better written. How?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

草莓味的萝莉 2024-08-30 12:00:59

我知道您只想使用 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>(); 

I know you want to use only LINQ, but maybe a mix with XPath simplifies your code:

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>(); 
等风也等你 2024-08-30 12:00:59

我将使用扩展方法语法,并制作如下所示的 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;
    }

这仅进行名称匹配。但您可以使用这些方法作为构建块。无论您在何处查询此类文档,都可以重复使用名称部分匹配,因此不可重复使用的部分很小。查询的后半部分可以从此示例导出。

I would use the Extension method syntax, and make Linq filter methods like below:

    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;
    }

This only does the name matching. But you can use these methods as buildingblocks. You can reuse the name part matching wherever you query this type of document, so the non-reusable portion is small. The second half of the query can be derived from this example.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文