Reputation: 22652
I have referred XPathSelectElement select the second when there is more than one and XPath and XPathSelectElement. But this is a different question.
I have following xml. I need to find out the Message element value (from StatusDetail) corresponding to Sequence 2. If there is no sequence 2 present, it should return null. What is the best way to do this in C# using XPathSelectElement
?
Note: There can be any number of StatusDetail (or not at all)
Note: The StatusDetail element can be in any order. We need to look only for the value “2” in 2
CODE
XDocument xDoc = XDocument.Parse(@"
<Status>
<StatusMsg>
<StatusType>INVOICE</StatusType>
<StatusCode>READYPAY</StatusCode>
<StatusTimestamp>2013-03-19T21:20:54Z</StatusTimestamp>
<StatusDetail>
<Sequence>1</Sequence>
<Message>.Document posted successfully </Message>
</StatusDetail>
<StatusDetail>
<Sequence>2 </Sequence>
<Message>Invoice is ready for pay</Message>
</StatusDetail>
</StatusMsg>
</Status>
");
var statusDetails = xDoc.XPathSelectElements(@"Status/StatusMsg/StatusDetail");
UPDATE
Following is the solution that I am using based on the selected answer
var statusDetails = xDoc.XPathSelectElements(@"Status/StatusMsg/StatusDetail/Sequence[text()=2]/../Message").FirstOrDefault();
if (statusDetails != null)
{
selectedMessage = statusDetails.Value;
}
Upvotes: 0
Views: 448
Reputation: 125610
var statusDetails = xDoc.XPathSelectElements(@"Status/StatusMsg/StatusDetail/Sequence[text()=2]/../Message");
It uses text()
to select element by its value and parent selector /..
to get back from that element to its parent.
Add ToList()
or SingleOrDefault
to enumerate results and save it into a list or single XElement
object.
Update
LINQ to XML query version:
var results = from sd in xDoc.Root.Elements("StatusMsg").Elements("StatusDetail")
let s = sd.Element("Sequence")
where s != null && ((string)s).Trim() == "2"
select (string)sd.Element("Message");
and with Method-based query:
results = xDoc.Root.Elements("StatusMsg").Elements("StatusDetail")
.Select(sd => new { sd, s = sd.Element("Sequence") })
.Where(x => x.s != null && ((string)x.s).Trim() == "2")
.Select(x => (string)x.sd.Element("Message"))
You can add another .Where(x => x != null)
to skip null
results (which exists when there is StatusDetail
with Seqience == 2
, but no Message
element.
Upvotes: 1
Reputation: 75296
Why not using LINQ to XML:
var result = xDoc.Descendants("StatusDetail")
.Where(x =>
{
var xElement = x.Element("Sequence");
return xElement != null && xElement.Value.Trim() == "2";
})
.Select(x => (string)x.Element("Message"))
.SingleOrDefault();
Upvotes: 1