I've been struggling all day to query an XDocument instance, the XPath query I am trying to use seems fairly straightforward:
//OrderResponseHeader/ListOfReferenceCoded[.//ReferenceTypeCoded = 'AgreementNumber']//RefNum
Translating this query into Linq To Xml was neither intuitive nor extensible. So I looked at using the XPathSelectElement[s] extension, and found one major problem with the implementation - it cannot handle default namespaces without a prefix, which the XDocument I am querying against has.
This means that in order for my query to work I would have to amend it include a prefix before each element name. This is not ideal, and the potential for error increases.
After much of the afternoon Googling for an answer, I eventually came across a simple solution on the MSDN forums which removes all namespaces from an XDocument instance. Here is how I have implemented it:
private XDocument RemoveNamespace(XDocument xdoc)
{
foreach (XElement e in xdoc.Root.DescendantsAndSelf())
{
if (e.Name.Namespace != XNamespace.None)
{
e.Name = XNamespace.None.GetName(e.Name.LocalName);
}
if (e.Attributes().Where(a => a.IsNamespaceDeclaration || a.Name.Namespace != XNamespace.None).Any())
{
e.ReplaceAttributes(e.Attributes().Select(a => a.IsNamespaceDeclaration ? null : a.Name.Namespace != XNamespace.None ? new XAttribute(XNamespace.None.GetName(a.Name.LocalName), a.Value) : a));
}
}
return xdoc;
}
And now I can query directly on the XDocument using XPathSelectElement:
AgreementNumber = message.XPathSelectElement("//OrderResponseHeader/ListOfReferenceCoded[.//ReferenceTypeCoded='AgreementNumber']//RefNum").Value