2

C# で XML ファイルから情報を取得する必要があります。

XML の一部を次に示します。

<Surface id="su-62" surfaceType="InteriorWall">
    <Name>S-3-7-I-W-62</Name>
    <AdjacentSpaceId spaceIdRef="sp-3-TUIN">
    </AdjacentSpaceId>
    <AdjacentSpaceId spaceIdRef="sp-7-huizen">
    </AdjacentSpaceId>
    <CADObjectId>Basic Wall: _omgevingsmuur [184610]</CADObjectId>
</Surface>
...
<Surface id="su-63" surfaceType="ExteriorWall">
    <Name>N-4-E-W-63</Name>
    <AdjacentSpaceId spaceIdRef="sp-4-onthaal">
    </AdjacentSpaceId>
    <Opening id="su-63-op-1" openingType="NonSlidingDoor">
    </Opening>
    <CADObjectId>Basic Wall: _detentiemuur [193431]</CADObjectId>
</Surface>  
...
<Surface id="su-282" surfaceType="Shade">
    <Name>X-S-282</Name>
    <CADObjectId>Basic Roof: Generic - 400mm [190976]</CADObjectId>
</Surface>

ご覧のとおり、他のサーフェスが持っているすべての情報を持っていないサーフェスがいくつかあります。どの面がどの空間に隣接しているか、開口部があるかどうかを知る必要があります。

(最終的な目標は、どの SPACE がどの SPACE に隣接しているかを確認できる 2D 配列と、結合された開口部があるかどうかを確認する別の配列を作成することです。)

4

1 に答える 1

0

.NET 3.5 以降を使用していると仮定すると、これはLINQ2XMLの適切な使用法です。

関連付けられた領域を取得し、どの領域が互いに隣接しているかを識別するクエリを作成できます。

// Load your XML File into an XDocument object
var xDoc = XDocument.Load(xmlPath);

// this is your query, in the end result with my a Dictionary with the Surface 
//  Id attribute as the key and the AdjacentSpaceId as the value
var result = (from x in xDoc.Descendants("AdjacentSpaceId")
              select new
              {
                  SurfaceId = (String)x.Parent.Attribute("id"),
                  SurfaceName = (String)x.Parent.Element("Name"),
                  AdjacentSpace = (String)x
              }).GroupBy(sp => sp.SurfaceId)
                .ToDictionary(grp => grp.Key,
                              grp => grp.Select(value => value.AdjacentSpace));

LINQ のバリエーションに慣れていない場合は、クエリについてもう少し詳しく説明します。クエリ結果を含むローカル フィールドは単に と呼ばれresultsます。型は、var式の右側で型を識別するようにコンパイラに指示する別の .NET 3.5 追加機能です。この場合、resultになりますDictionary<String, IEnumerable<String>>

クエリの最初の行で:

from x in xDoc.Descendants("AdjacentSpaceId")

基本的に、LINQ に という XML 内のすべてのノードを反復処理するように指示していますAdjacentSpaceId。これらのノードがどこにあるか、または親ノードが何と呼ばれているかは問題ではありません。LINQのDescendants()メソッドは、特定のノードを選択するために正確な XML パスを知る必要がなく、名前だけが必要であることを意味するため、この理由で非常に強力です (最後のメモを参照してください)。

クエリの次の行は、クエリから何を返したいかを正確に定義しています。

  select new
  {
      SurfaceId = (String)x.Parent.Attribute("id"),
      SurfaceName = (String)x.Parent.Element("Name"),
      AdjacentSpace = (String)x
  })

この構文を使用するすべての LINQ クエリには、selectステートメントが必要です (必ずしも select を必要としない代わりに、または追加で使用できるメソッド構文もありますが、私の意見では、この構文の方が習得が容易です)。

select 句では、基本的に、、およびの 3 つのプロパティを持つ新しい匿名型を定義しています。割り当ての 1 つを説明すると、それらすべてを理解できるはずです。SurfaceIdSurfaceNameAdjacentSpace

SurfaceId = (String)x.Parent.Attribute("id")

この行の は、すべてのノードxを繰り返し処理していた LINQ クエリの最初の行を指しているため、タイプはです。 AdjacentSpaceIdxXElement

Parentプロパティはx、この場合は親ノードを選択しますSurface。(注: XML のルート ノードがたまたま呼び出された場合、ルート ノードAdjacentSpaceIdの親が null になるため、この行は例外をスローしますが、問題にはならないという安全な仮定のようです。この場合)。onのParentプロパティXElementも別のものになりますXElement

次の部分は のAttributeメソッドでXElement、 というノードの最初のアトリビュートを選択していますid

idしたがって、効果的に、すべての親ノードの属性を各ノードに選択していますAdjacentSpaceId

最後に、これを文字列にキャストしています。Value代わりに使用できるプロパティがありますが、Attribute("id")メソッドが失敗した場合 (「id」という属性がない場合に発生する可能性があります)、Valueプロパティを呼び出すと例外がスローされるため、私の個人的な好みは文字列にキャストすることです。これらの場合、文字列に null を返すだけです。

この select 句の他の部分は実質的に同じです。

このクエリの残りの部分は、事実上個別のクエリです。私はそれらを連鎖させただけでしたが、簡単に分解して単独で配置することができました.

次の作品:

GroupBy(sp => sp.SurfaceId)

LINQ クエリの結果をSurfaceIdプロパティでグループ化しています。スペースが各サーフェスに隣接している場所を知りたいと思われるため、これは重要なステップです。これにより、隣接するすべてのスペースがサーフェスによって効果的にグループ化されます。

慣れていない場合sp => sp.SurfaceIdは、匿名関数またはデリゲートをすばやく簡単に作成するためのラムダ式です。

そして最後の部分は、グループ化された結果を取得し、それらをより使いやすいものに変換します。通常はDictionary<>、この場合はDictionary<String, IEnumerable<String>>

ToDictionary(grp => grp.Key,
             grp => grp.Select(value => value.AdjacentSpace));

Linq-to-Xml オブジェクトの拡張メソッドについては、Descendants()前述のように非常に便利な場合もありますが、非常に危険な場合もあります。同じ XML 内に同じ名前で目的が異なる複数のノードがある場合、またはツリーの親が異なる場合、Descendants()はすべてのオブジェクトを返します。特定の名前に一致するノードの一部のみを返したい場合は、最初にElement()またはElements()拡張メソッドを使用して適切な親ノードを選択することにより、最初にそれをフィルタリングする必要があります。その後、 を安全に呼び出すことができますDescendants()

于 2012-11-14T10:30:25.327 に答える