85 votes

Ignorer les espaces de noms dans LINQ to XML

Comment dois-je LINQ to XML iqnore tous les espaces de noms? Ou alteranately, comment je bande les espaces de noms?

Je demande parce que les espaces de noms sont mis dans un état de semi-aléatoire de la mode et je suis fatigué d'avoir à les chercher pour les nœuds à la fois avec et sans espace de noms.

135voto

Pavel Minaev Points 60647

Au lieu d'écrire:

nodes.Elements("Foo")

écrire:

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

et quand vous êtes fatigué, faites votre propre méthode d'extension:

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

Idem pour les attributs, si vous avez à traiter avec espace de noms d'attributs souvent (ce qui est relativement rare).

[EDIT] Ajout de la solution de XPath

Pour XPath, au lieu d'écrire:

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

vous pouvez utiliser local-name() fonction de:

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

15voto

Ahmad Mageed Points 44495

Voici une méthode pour la bande des espaces de noms:

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

Exemple d'utilisation:

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

4voto

Jobo Points 869

Comme je trouve cette question à la recherche d'un moyen facile d'ignorer les espaces de noms sur les attributs, voici une extension pour ignorer les espaces de noms lors de l'accès à un attribut, basé sur Pavels réponse (pour faciliter la copie j'ai compris son 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);
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X