2009-08-26 5 views
0

previous question에서 논리적으로 XML 요소를 그룹화하는 방법에 대해 물어 보았습니다. 그 대답은 Linq 쿼리를 중첩하는 것이 었습니다.Linq/XML : XML 요소 내에서 그룹화 결과가 올바르게 표시됩니다. 내부 조인을 사용합니다!

문제는 이것이 중첩 쿼리를 왼쪽으로 결합하는 효과가 있다는 것입니다.

XElement xml = new XElement("States", 
    from s in LinqUtils.GetTable<State>() 
    orderby s.Code 
    select new XElement("State", 
    new XAttribute("Code", s.Code), 
    new XAttribute("Name", s.Name), 
    from cy in s.Counties 
    orderby cy.Name 
    select new XElement("County", 
     new XAttribute("Name", cy.Name), 
     from c in cy.Cities 
     where c.Name.StartsWith("Y") 
     orderby c.Name 
     select new XElement("City", 
     new XAttribute("Name", c.Name) 
    ) 
    ) 
) 
); 

Console.WriteLine(xml); 

이 출력 :

<States> 
    <State Code="AK" Name="Alaska "> 
    <County Name="ALEUTIANS EAST" /> 
    <County Name="ALEUTIANS WEST" /> 
    <County Name="ANCHORAGE" /> 
    <County Name="BETHEL" /> 
    ... 
    <County Name="YAKUTAT"> 
     <City Name="YAKUTAT" /> 
    </County> 
    <County Name="YUKON KOYUKUK" /> 
    </State> 
    <State Code="AL" Name="Alabama "> 
    <County Name="AUTAUGA" /> 
    ... 
    etc. 

나는 '돈 예를 들어, 내가 모든 국가별로 그룹화 문자 "Y"로 시작하는 미국의 도시와 카운티를 나열하고 싶은 말은하자 왼쪽 결합 효과를 원한다. 나는 문자 "Y"로 시작하는 도시를 실제로 포함하는 주와 카운티를보고 싶습니다.

나는 이것을 할 수있는 몇 가지 방법을 생각할 수 있지만, 모두가 끈적하고 우아하지 않은 것처럼 보입니다. 원하는 효과를 얻기 위해 생각할 수있는 가장 깨끗한 방법은 무엇입니까?

답변

2

이 문제를 해결하는 데는 여러 가지 방법이 있지만 매우 우아하지는 않습니다. 몇 가지 옵션 :

옵션 1 :

XElement xml = new XElement("States", 
    from s in LinqUtils.GetTable<State>() 
    let counties = from cy in s.Counties 
       let cities = from c in cy.Cities 
           where c.Name.StartsWith("Y") 
           orderby c.Name 
           select new XElement("City", 
           new XAttribute("Name", c.Name) 
          ) 
       where cities.Any() 
       orderby cy.Name 
       select new XElement("County", 
        new XAttribute("Name", cy.Name), 
        cities   
       ) 
    where counties.Any() 
    orderby s.Code 
    select new XElement("State", 
    new XAttribute("Code", s.Code), 
    new XAttribute("Name", s.Name), 
    counties 
) 
); 

옵션 2 : 하위 쿼리를 캡처하고 빈 값을 필터링 let를 사용하는 대신 별개의에 의해 그룹과 내면의 결합 방식을 사용

XElement xml = new XElement("States", 
    from s in LinqUtils.GetTable<State>() 
    from cy in s.Counties 
    from c in cy.Cities 
    where c.Name.StartsWith("Y") 
    group new { cy, c } by s into gs 
    let s = gs.Key 
    orderby s.Code 
    select new XElement("State", 
    new XAttribute("Code", s.Code), 
    new XAttribute("Name", s.Name), 

    from g in gs 
    group g.c by g.cy into gcy 
    let cy = gcy.Key 
    orderby cy.Name 
    select new XElement("County", 
     new XAttribute("Name", cy.Name), 

     from c in gcy 
     orderby c.Name 
     select new XElement("City", 
     new XAttribute("Name", c.Name) 
    ) 
    ) 
) 
); 
+0

우수! 익명 유형을 사용하여 중첩 된 그룹화를 수행하는 방법을 알려 주셔서 감사합니다. :) –

0

첫 번째 방법은 먼저 올바른 내부 조인을 모두 포함하는 쿼리를 만든 다음 Distinct() 필터를 사용하여 외부 그룹을 만든 다음 where 절을 사용하여 그룹화하여 XML을 만듭니다. 따라서 :

var Cities = from s in LinqUtils.GetTable<State>() 
      from cy in s.Counties 
      from c in cy.Cities 
      where c.Name.StartsWith("Y") 
      select c; 

var States = Cities.Select(c => c.County.State).Distinct(); 
var Counties = Cities.Select(c => c.County).Distinct(); 

XElement xml = new XElement("States", 
    from s in States 
    orderby s.Code 
    select new XElement("State", 
    new XAttribute("Code", s.Code), 
    new XAttribute("Name", s.Name), 
    from cy in Counties 
    where cy.StateCode == s.Code 
    orderby cy.Name 
    select new XElement("County", 
     new XAttribute("Name", cy.Name), 
     from c in Cities 
     where c.CountyID == cy.ID 
     orderby c.Name 
     select new XElement("City", 
     new XAttribute("Name", c.Name) 
    ) 
    ) 
) 
); 

그것은 작동하지만, 어떻게 든 더 나은 방법이 있다는 느낌이 ...

1

난 당신이 좋은 시작을 생각합니다. Cities 목록에 국가 및 주에 대한 정보를 추가 한 다음 group by 목록에 두 번째 조인 및 필터를 사용하지 않아도됩니다.
큰 linq 쿼리에서이 작업을 수행 할 수도 있습니다.

dirs = new List<DirectoryInfo>(); 
dirs.Add(new DirectoryInfo("c:\\")); 
dirs.Add(new DirectoryInfo("c:\\windows\\")); 

var a = from directory in dirs 
     from file in directory.GetFiles() 
     where file.Name.StartsWith("a") 
     group file by directory.Name into fileGroup 
     select new XElement("Directory", new XAttribute("path", fileGroup.Key), 
      from f in fileGroup 
      select new XElement("File", f.Name) 
      ); 

XDocument doc = new XDocument(new XElement("Folders", a)); 

는 XML 결과 :

<Folders> 
    <Directory path="c:\"> 
    <File>ActiveDirectoryService.cs</File> 
    <File>ApplicationTemplateCore.wsp</File> 
    <File>AUTOEXEC.BAT</File> 
    </Directory> 
    <Directory path="windows"> 
    <File>adfs.msp</File> 
    <File>adminscript2nd.exe</File> 
    <File>aspnetocm.log</File> 
    </Directory> 
</Folders> 
그것은 (다른 레벨을 추가해야합니다) 정확하게 자신의 클래스를 가지고 있지만, 여기에 파일 및 폴더와 비슷한이기 때문에 당신이 필요로 쓰기 어렵다

다시 여기 키는 group by을 결과에 사용하는 것입니다.

+0

Toda rabba ...하지만 group-by의 이중 중첩에 어려움을 겪고 있습니다. State-> County-> City와 같이 이중 중첩을 수행하는 방법에 대한 예를 들어 주시겠습니까? 감사! –

관련 문제