私は最近、Linq to XML クエリの一部として XPath を使用しなければならない状況に遭遇し、それが少し奇妙に動作することに気付きました。ネイティブの XElement API メソッドを使用して問題を解決する方法は他にもあると思いますが、この状況では、ドキュメント構造が非常に複雑なため、必要な特定の XML テキスト値を見つけるには XPath がはるかに適していました。私は最終的にそれを機能させる方法を見つけましたが (以下を参照)、あまりきれいではありませんでした。
私の質問は、XPathEvaluteまたはその他の XPath メソッドを使用して、where ステートメントで、または select メソッドの新しいオブジェクトの一部として使用できる文字列値を返す方法です。LINQ で多くのキャストと Null 合体演算子を使用するソリューションを見つけましたが、よりクリーンな方法が必要です。問題の根本は、XPathEvaluate メソッドが通常 XText 要素 (汎用オブジェクトにキャスト) を返すことですが、Linq はそれを IEnumerable に変換して実行を遅らせることができることです。クエリが実行されるまで実体化されないため、そのオブジェクトの値にアクセスしようとすると問題が発生します。
次に例を示します。次の XML ドキュメントを使用して、同じ名前の男の子と女の子を持つすべての親を検索します。私の状況ではドキュメント構造が非常に複雑だったため、これは XPath クエリを使用して行う必要があります。
//Use C# Program Language type in LinqPad
void Main()
{
var xml = XElement.Parse(@"<Root>
<Parent>
<Boy>Anne</Boy>
</Parent>
<Parent>
<Boy>Alex</Boy>
<Girl>Alex</Girl>
</Parent>
<Parent>
<Boy>Jay</Boy>
</Parent>
</Root>");
var q1 = from e in xml.XPathSelectElements("/Parent")
select e;
q1.Dump();
var q2 = from e in q1
let boy = ((IEnumerable<Object>)e.XPathEvaluate("Boy/text()")).Cast<System.Xml.Linq.XText>().FirstOrDefault() ?? new System.Xml.Linq.XText("")
let girl = ((IEnumerable<Object>)e.XPathEvaluate("Girl/text()")).Cast<System.Xml.Linq.XText>().FirstOrDefault() ?? new System.Xml.Linq.XText("")
select new {t=boy.GetType(), b=boy, g=girl, same=(boy.Value==girl.Value)};
q2.Dump();
}
結果は次のとおりです。
2 番目の要素は、同じ名前の男の子と女の子を持つものとして識別されていることがわかります。まだXPathを使用している間にこれを行うよりクリーンな方法はありますか、それとも上記のコードを使用して立ち往生していますか?