2010-03-01 9 views
2

J'ai une collection de disques Mods qui ressemble à ceci:Comment rendre cette requête LINQ to XML plus élégante?

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

Ma requête LINQ pour rechercher le colloction pour les enregistrements affiliés à une certaine personne avec un certain rôle ressemble à ceci:

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

Je pense que cette requête pourrait être mieux écrite. Comment?

+0

Juste pour clearyfy: Je suis à la recherche d'un bon exemple sur une requête LINQ où des conditions différentes sont mises sur plusieurs noeuds délendants. – Fontanka16

Répondre

2

Je sais que vous voulez utiliser seulement LINQ, mais peut-être un mélange avec XPath simplifie votre 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>(); 
2

Je voudrais utiliser la syntaxe de la méthode d'extension, et rendre les méthodes de filtrage Linq comme ci-dessous:

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

Ceci correspond uniquement au nom. Mais vous pouvez utiliser ces méthodes comme buildingblocks. Vous pouvez réutiliser la partie nom correspondant à chaque fois que vous interrogez ce type de document, de sorte que la partie non réutilisable est petite. La seconde moitié de la requête peut être dérivée de cet exemple.