2012-11-18 4 views
0

XDocument의 특정 하위 노드에 새로 만든 객체를 직렬화하고 삽입하려고합니다. 나는 이것을 달성 할 수 있었지만 나의 코드는 냄새 나는 것처럼 보인다.상위 노드 필터링 linq

아래에서 수행 한 것처럼 Parent 속성을 통해 체인을 연결하지 않고 어떻게 상위 노드 속성 값을 테스트 할 수 있습니까?

var elements = (
    from army in xdoc.Descendants("Army") 
    where army.Attribute("name").Value == _ArmyName 
    from unitCategory in army.Descendants("UnitCategory") 
    where unitCategory.Attribute("name").Value == _UnitCategoryName 
    from unitType in unitCategory.Descendants("UnitType") 
    where unitType.Attribute("name").Value == _UnitTypeName 
    from unit in unitType.Descendants("Unit") 
    select unit 
    ); 

참고 :

<?xml version="1.0" encoding="utf-8"?> 
<ArrayOfArmy> 
    <Army name="Tyranid"> 
    <unit-category> 
     <UnitCategory name="Troops"> 
     <unit-type> 
      <UnitType name="Infantry"> 
      <unit> 
       <Unit points="5" name="Hornmagant" composition="20" weapon-skill="3" ballistic-skill="100" strength="3" toughness="4" wounds="1" initiative="3" attacks="3" leadership="5" saving-throw="6+" armour="Chitin" weapons="Many" special-rules="None" dedicated-transport="No" options="8"> 
       <Amount>0</Amount> 
       </Unit> 
       <Unit points="5" name="Termagant" composition="20" weapon-skill="3" ballistic-skill="100" strength="3" toughness="4" wounds="1" initiative="3" attacks="3" leadership="5" saving-throw="6+" armour="Chitin" weapons="Many" special-rules="None" dedicated-transport="No" options="8"> 
       <Amount>0</Amount> 
       </Unit> 
      </unit> 
      </UnitType> 
     </unit-type> 
     </UnitCategory> 
    </unit-category> 
    </Army> 
</ArrayOfArmy> 

답변

1

당신은 중첩 된 foreach 루프를 사용하는 것과 비슷 compound from clauses을 사용할 수 있습니다

XDocument xdoc = XDocument.Load(path); 

var elements = (
    from doc in xdoc.Descendants("Unit") 
    where doc.Parent.Parent.Attribute("name").Value == _UnitTypeName && 
    doc.Parent.Parent.Parent.Parent.Attribute("name").Value == _UnitCategoryN 
    doc.Parent.Parent.Parent.Parent.Parent.Parent.Attribute("name").Value == 
    select doc 
    ); 

foreach (var element in elements) 
{ 
    Unit unit = 
     new Unit 
     { 
      Armour = _Armour, 
      Attacks = _Attacks, 
      BallisticSkill = _BallisticSkill, 
      Composition = _Composition, 
      DedicatedTransport = _DedicatedTransport, 
      Initiative = _Initiative, 
      Leadership = _Leadership, 
      Options = _Options, 
      SaveThrow = _SaveThrow, 
      SpecialRules = _SpecialRules, 
      Strength = _Strength, 
      Toughness = _Toughness, 
      UnitName = _UnitName, 
      Weapons = _Weapons, 
      WeaponSkill = _WeaponSkill, 
      Wounds = _Wounds, 
      Points = _Points 
     }; 

    XmlSerializer serializer = new XmlSerializer(typeof(Unit)); 
    using (var stream = new MemoryStream()) 
    { 
     XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); 
     ns.Add("", ""); 
     serializer.Serialize(stream, unit, ns); 
     stream.Position = 0; 

     //using (XmlReader reader = XmlReader.Create(stream)) 
     //{ 
     // XElement xe = XElement.Load(reader); 
     XElement xe = XElement.Load(@"C:\Test\tempfile.xml"); // For some reason loading via MemoryStream messes with xml formatting 
     element.AddBeforeSelf(xe); 
     //} 
    } 
    break; 
} 
xdoc.Save(path); 

는 XML 문서의 구조 방법 구문 상당은 SelectMany()입니다.

+0

고마워요! 동일한 결과를 얻기 위해'where' 필터를 가진 절에 대한 컴파운드를 사용하면 훨씬 더 읽기 쉽습니다! – Amicable

+0

@Amicable : 당신이 내 대답에서 당신이 필요로하는 것을 기쁘게 생각합니다. 미래의 독자를 혼란스럽게하기 위해 내 쿼리가 원래의 쿼리와 일치하는지 확인하려고합니다. 새 쿼리가 어떻게 생겼는지 편집 된 답변입니까? 나는 XML에 대한 경험이별로 없으며 대문자와 소문자로 인해 저를 버렸습니다. –

+0

하이픈이있는 노드에는 특성이 없으므로 이름을 쿼리하는 Null 참조를 얻게됩니다. 이 노드들은 직렬화 된'List '을 나타낸다. 편집을위한 글자 수 제한을 만들기 위해 무작위로'/'를 써야했습니다. – Amicable