Soru LINQ'da XML alan adlarını yoksay


XML için LINQ'a nasıl sahip olabilirim? Ya da alternatif olarak, ad alanlarını nasıl çıkaracağım?

Ben sorarım çünkü ad alanları yarı-rasgele bir şekilde ayarlanmış ve bir isim ile ve isimsiz olarak düğümleri aramak zorunda kalmaktan yoruldum.


76
2017-07-17 20:59


Menşei


Ayrıca bakınız XPath XML ad alanları ile nasıl ilgilenir? - kjhughes


Cevaplar:


Yazmak yerine:

nodes.Elements("Foo")

yazmak:

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

ve bıktığınızda, kendi uzatma yönteminizi yapı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);
}

Nitelikli isimlerle uğraşmak zorunda kalıyorsanız, çoğu zaman (nispeten nadirdir) ad alan özelliklerle uğraşmak zorunda kalırsınız.

[DÜZENLE] XPath için çözüm ekleme

XPath için yazmak yerine:

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

kullanabilirsiniz local-name() fonksiyon:

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

124
2017-07-17 21:03



Bu kesinlikle benim problemimin yarısını çözüyor. Ama bunu XPath ifadeleri ile nasıl yaparım? - Jonathan Allen
Güncellenen cevaba bakınız. - Pavel Minaev
İstediğiniz öğenin benzersiz olarak adlandırıldığını biliyorsanız, tüm ara öğeleri aşağıdakilerle atlayabilirsiniz: xDoc.Root.Descendants().Where(e => e.Name.LocalName == "SomeName"); - AaronLS


İşte ad alanlarını soyma yöntemi:

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

Örnek kullanım:

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





Öznitelikteki ad alanlarını görmezden gelmenin kolay bir yolunu bulmak için bu soruyu bulduğumda, bir özelliğe erişirken, Pavel'ın cevabına dayanarak ad alanlarını göz ardı etmek için bir uzantı bulunuyor (daha kolay kopyalama için uzantısını ekledim):

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