あなたの質問が正しいと理解できれば、 attribute を持つ最も内側の要素のみを取得したいと考えていますResultCode="ERROR"
。の子要素があるため、サンプルデータ<PRODUCT>
は結果に含まれるべきではありませんResultCode="ERROR"
。
このDescendants
メソッドは、ドキュメント内のすべての子孫要素を返します。したがって、属性のみによるフィルタリングには、<PRODUCT>
ノードが含まれます。したがって、各要素の子のチェックを追加する必要があります。
var doc = XDocument.Load("Test.xml");
var errors = doc.Descendants()
.Where(e => e.Attribute("ResultCode") != null &&
e.Attribute("ResultCode").Value == "ERROR" &&
!e.Elements().Any(c => c.Attribute("ResultCode") != null &&
c.Attribute("ResultCode").Value == "ERROR"));
これは、エラーのある子を持たない要素のみを返します。
ResultCode
XML の各ノードに属性がある場合は、null のチェックを省略できることに注意してください。そうでない場合は、NullReferenceException
. そのチェックのための小さなヘルパーメソッドを書くことをお勧めします:
public static bool HasError(XElement element)
{
var resultCode = element.Attribute("ResultCode");
return resultCode != null && resultCode.Value == "ERROR";
}
var errors = doc.Descendants()
.Where(e => HasError(e) && !e.Elements().Any(c => HasError(c)));
ResultCode="ERROR"
親にエラーがない場合でも、これは要素を返すことに注意してください。
親にもエラーがある場合にのみ要素を結果に含める必要があるという要件がある場合、および XML が常にそのように形成されるかどうかわからない場合は、再帰関数を記述する必要があります。
public static IEnumerable<XElement> InnermostErrors(XElement root)
{
var resultCode = root.Attribute("ResultCode");
if (resultCode == null || resultCode.Value != "ERROR")
{
yield break;
}
var childrenWithError = root.Elements().Where(e => HasError(e));
if (!childrenWithError.Any())
{
yield return root;
}
foreach (var inner in childrenWithError.SelectMany(e => InnermostErrors(e)))
{
yield return inner;
}
}