Bỏ qua không gian tên trong LINQ sang XML


87

Làm cách nào để có LINQ đến XML iqnore tất cả các không gian tên? Hoặc thay vào đó, làm cách nào để loại bỏ các không gian tên?

Tôi đang hỏi vì không gian tên đang được đặt theo kiểu bán ngẫu nhiên và tôi mệt mỏi khi phải tìm kiếm các nút có và không có không gian tên.


Câu trả lời:


137

Thay vì viết:

nodes.Elements("Foo")

viết:

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

và khi bạn cảm thấy mệt mỏi với nó, hãy tạo phương pháp mở rộng của riêng bạn:

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 cho các thuộc tính, nếu bạn phải xử lý các thuộc tính không gian tên thường xuyên (tương đối hiếm).

[EDIT] Thêm giải pháp cho XPath

Đối với XPath, thay vì viết:

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

bạn có thể sử dụng local-name()chức năng:

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

Nếu bạn biết các yếu tố bạn muốn được đặt tên duy nhất, bạn có thể bỏ qua tất cả các yếu tố trung gian với:xDoc.Root.Descendants().Where(e => e.Name.LocalName == "SomeName");
AaronLS

17

Đây là một phương pháp để loại bỏ không gian tên:

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

Ví dụ sử dụng:

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

4

Khi tôi tìm thấy câu hỏi này để tìm kiếm một cách dễ dàng để bỏ qua không gian tên trên các thuộc tính, đây là một tiện ích để bỏ qua không gian tên khi truy cập một thuộc tính, dựa trên câu trả lời của Pavel (để sao chép dễ dàng hơn, tôi đã bao gồm tiện ích mở rộng của anh ấy):

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);
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.