Câu hỏi Bỏ qua các không gian tên trong LINQ thành XML


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

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


76
2017-07-17 20:59


gốc


Xem thêm XPath đối phó với các không gian tên XML như thế nào? - kjhughes


Các câu trả lời:


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, 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 đối phó với 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ể dùng local-name() chức năng:

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

124
2017-07-17 21:03



Điều đó chắc chắn giải quyết được một nửa vấn đề của tôi. Nhưng làm thế nào tôi có thể làm điều đó với các biểu thức XPath? - Jonathan Allen
Xem câu trả lời được cập nhật. - Pavel Minaev
Nếu bạn biết phần tử bạn muốn được đặt tên duy nhất, bạn có thể bỏ qua tất cả các phần tử trung gian với: xDoc.Root.Descendants().Where(e => e.Name.LocalName == "SomeName"); - AaronLS


Dưới đây là một phương pháp để loại bỏ các 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;
}

Sử dụng ví dụ:

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

15
2017-07-18 08:24





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 các không gian tên trên thuộc tính, đây là phần mở rộng để bỏ qua các không gian tên khi truy cập 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 phần 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);
}

4
2018-01-29 16:01