Ignore namespaces in LINQ to XML

前端 未结 3 1537
北荒
北荒 2020-11-28 06:20

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-rando

相关标签:
3条回答
  • 2020-11-28 06:29

    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);
    }
    
    0 讨论(0)
  • 2020-11-28 06:33

    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);
    
    0 讨论(0)
  • 2020-11-28 06:36

    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).

    [EDIT] Adding solution for XPath

    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']
    
    0 讨论(0)
提交回复
热议问题