How do I have LINQ to XML iqnore all namespaces? Or alteranately, how to I strip out the namespaces?
I'm asking because the namespaces are being set in a semi-random fashion and I'm tired of having to search for nodes both with and without a namespace.
Since in this case you have a default namespace defined, you could just remove the default namespace declaration and add a new declaration for your new prefix using the old namespace name, effectively replacing it.
To create an attribute that declares a namespace with a prefix, you create an attribute where the namespace of the name of the attribute is Xmlns, and the name of the attribute is the namespace prefix. The value of the attribute is the URI of the namespace.
Instead of writing:
nodes.Elements("Foo")
write:
nodes.Elements().Where(e => e.Name.LocalName == "Foo")
and when you get tired of it, make your own extension method:
public static IEnumerable<XElement> ElementsAnyNS<T>(this IEnumerable<T> source, string localName)
where T : XContainer
{
return source.Elements().Where(e => e.Name.LocalName == localName);
}
Ditto for attributes, if you have to deal with namespaced attributes often (which is relatively rare).
For XPath, instead of writing:
/foo/bar | /foo/ns:bar | /ns:foo/bar | /ns:foo/ns:bar
you can use local-name()
function:
/*[local-name() = 'foo']/*[local-name() = 'bar']
Here's a method to strip namespaces:
private static XElement StripNamespaces(XElement rootElement)
{
foreach (var element in rootElement.DescendantsAndSelf())
{
// update element name if a namespace is available
if (element.Name.Namespace != XNamespace.None)
{
element.Name = XNamespace.None.GetName(element.Name.LocalName);
}
// check if the element contains attributes with defined namespaces (ignore xml and empty namespaces)
bool hasDefinedNamespaces = element.Attributes().Any(attribute => attribute.IsNamespaceDeclaration ||
(attribute.Name.Namespace != XNamespace.None && attribute.Name.Namespace != XNamespace.Xml));
if (hasDefinedNamespaces)
{
// ignore attributes with a namespace declaration
// strip namespace from attributes with defined namespaces, ignore xml / empty namespaces
// xml namespace is ignored to retain the space preserve attribute
var attributes = element.Attributes()
.Where(attribute => !attribute.IsNamespaceDeclaration)
.Select(attribute =>
(attribute.Name.Namespace != XNamespace.None && attribute.Name.Namespace != XNamespace.Xml) ?
new XAttribute(XNamespace.None.GetName(attribute.Name.LocalName), attribute.Value) :
attribute
);
// replace with attributes result
element.ReplaceAttributes(attributes);
}
}
return rootElement;
}
Example usage:
XNamespace ns = "http://schemas.domain.com/orders";
XElement xml =
new XElement(ns + "order",
new XElement(ns + "customer", "Foo", new XAttribute("hello", "world")),
new XElement("purchases",
new XElement(ns + "purchase", "Unicycle", new XAttribute("price", "100.00")),
new XElement("purchase", "Bicycle"),
new XElement(ns + "purchase", "Tricycle",
new XAttribute("price", "300.00"),
new XAttribute(XNamespace.Xml.GetName("space"), "preserve")
)
)
);
Console.WriteLine(xml.Element("customer") == null);
Console.WriteLine(xml);
StripNamespaces(xml);
Console.WriteLine(xml);
Console.WriteLine(xml.Element("customer").Attribute("hello").Value);
As I found this question in search for an easy way to ignore namespaces on attributes, here's an extension for ignoring namespaces when accessing an attribute, based on Pavel´s answer (for easier copying, I included his extension):
public static XAttribute AttributeAnyNS<T>(this T source, string localName)
where T : XElement
{
return source.Attributes().SingleOrDefault(e => e.Name.LocalName == localName);
}
public static IEnumerable<XElement> ElementsAnyNS<T>(this IEnumerable<T> source, string localName)
where T : XContainer
{
return source.Elements().Where(e => e.Name.LocalName == localName);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With