【问题标题】:Ignore namespaces in LINQ to XML忽略 LINQ to XML 中的命名空间
【发布时间】:2015-10-16 07:47:57
【问题描述】:

如何让 LINQ to XML iqnore 所有命名空间?或者,如何去除命名空间?

我之所以这么问,是因为命名空间是以半随机方式设置的,而且我厌倦了必须搜索有和没有命名空间的节点。

【问题讨论】:

标签: .net xml linq


【解决方案1】:

而不是写:

nodes.Elements("Foo")

写:

nodes.Elements().Where(e => e.Name.LocalName == "Foo")

当你厌倦它时,制作你自己的扩展方法:

public static IEnumerable<XElement> ElementsAnyNS<T>(this IEnumerable<T> source, string localName)
    where T : XContainer
{
    return source.Elements().Where(e => e.Name.LocalName == localName);
}

属性同上,如果您必须经常处理命名空间属性(这种情况比较少见)。

[编辑] 为 XPath 添加解决方案

对于 XPath,不要写:

/foo/bar | /foo/ns:bar | /ns:foo/bar | /ns:foo/ns:bar

你可以使用local-name()函数:

/*[local-name() = 'foo']/*[local-name() = 'bar']

【讨论】:

  • 如果你知道你想要的元素是唯一命名的,你可以跳过所有中间元素:xDoc.Root.Descendants().Where(e =&gt; e.Name.LocalName == "SomeName");
【解决方案2】:

这是一种剥离命名空间的方法:

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;
}

使用示例:

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

【讨论】:

    【解决方案3】:

    当我在寻找忽略属性上的命名空间的简单方法时发现了这个问题时,这里有一个扩展,用于在访问属性时忽略命名空间,基于 Pavel 的回答(为了便于复制,我包括了他的扩展):

    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);
    }
    

    【讨论】:

      猜你喜欢
      • 2020-04-06
      • 1970-01-01
      • 1970-01-01
      • 2011-12-05
      • 2015-02-18
      • 1970-01-01
      • 1970-01-01
      • 2011-01-21
      相关资源
      最近更新 更多