I have xml that is sent by a third party and I want to validate it.
XElement xTree = XElement.Parse(@"<Container>
<TrackingReferences>
<TrackingReference>
<TrackingName>Donny</TrackingName>
<TrackingCodes>
<TrackingCode>
<Name></Name>
</TrackingCode>
<TrackingCode>
<Name>DisplayThis</Name>
</TrackingCode>
<TrackingCode>
<Name></Name>
</TrackingCode>
</TrackingCodes>
</TrackingReference>
</TrackingReferences>
</Container>");
IEnumerable<XElement> childList = xTree.Element("TrackingReferences").Descendants("TrackingReference").Where(
tr => (
tr.Element("TrackingName") != null && !tr.Element("TrackingName").IsEmpty && !String.IsNullOrEmpty(tr.Element("TrackingName").Value) &&
tr.Descendants("TrackingCodes").Any(
tc => tc.HasElements &&
tc.Elements("TrackingCode").Any(
code => code.Element("Name") != null && !code.Element("Name").IsEmpty && !String.IsNullOrEmpty(code.Element("Name").Value)
)
)
)
);
I can't figure out how to return the descendants that I would like.
The problem I have is that I only want the TrackingReference element to contain TrackingCode descendants when that TrackingCode has a Name element that isn't null or empty.
The below example returns:
<TrackingReference>
<TrackingName>Donny</TrackingName>
<TrackingCodes>
<TrackingCode>
<Name></Name>
</TrackingCode>
<TrackingCode>
<Name>DisplayThis</Name>
</TrackingCode>
<TrackingCode>
<Name></Name>
</TrackingCode>
</TrackingCodes>
</TrackingReference>
However in this example I don't want the first and third TrackingCode elements to be returned, just the second as this has a Name element with value, like this:
<TrackingReference>
<TrackingName>Donny</TrackingName>
<TrackingCodes>
<TrackingCode>
<Name>DisplayThis</Name>
</TrackingCode>
</TrackingCodes>
</TrackingReference>
This is the first time I've tried a LINQ query to XML so any advice on how to make the query more clean/efficient would be much appreciated, or if I'm going about this the wrong way.
Okay, it sounds like you want the TrackingCode
elements rather than the TrackingReference
elements, so it's actually pretty easy:
var query = doc.Descendants("TrackingReference")
// TODO: Filter based on TrackingName if you want...
.Descendants("TrackingCode")
.Where(x => !string.IsNullOrEmpty((string) x.Element("Name"));
This uses the fact that the explicit string conversion on XElement
will return null
if you call it with a null
operand.