web-dev-qa-db-fra.com

comment ignorer les espaces de noms avec XPath

Mon objectif est d'extraire certains nœuds de plusieurs fichiers XML avec plusieurs espaces de noms à l'aide de XPath. Tout fonctionne bien tant que je connais les URI de l'espace de noms. Le nom de l’espace de noms lui-même reste constant, mais les schémas (XSD) sont parfois générés par le client, c’est-à-dire inconnus de moi. Il me reste alors essentiellement trois choix:

  1. utilisez seulement un schéma pour l'espace de noms, en espérant que tout se passe bien (puis-je en être sûr?)

  2. récupérez les nœuds enfants du document et recherchez le premier nœud avec un URI d'espace de nom, en espérant qu'il existe, puis utilisez simplement l'URI, en espérant qu'il corresponde au bon. peut se tromper pour plusieurs raisons

  3. en quelque sorte, dites à xpath: "regardez, je ne me soucie pas des espaces de noms, il suffit de trouver TOUS les nœuds avec ce nom, je peux même vous dire le nom de l'espace de noms, mais pas l'URI". Et c'est la question ici ...

Ce n'est pas une réitération de nombreuses "mon expression xpath ne fonctionne pas parce que je ne suis pas au courant de la connaissance de l'espace de noms" comme indiqué ici ou ici . Je sais comment utiliser la conscience d'espace de noms. Juste pas comment s'en débarrasser.

93
kostja

Vous pouvez utiliser la fonction local-name() XPath. Au lieu de sélectionner un noeud comme

/path/to/x:somenode

vous pouvez sélectionner tous les nœuds et filtrer pour celui portant le nom local correct:

/path/to/*[local-name() = 'somenode']
140
Dirk Vollmar

Vous pouvez faire la même chose dans XPath2. dans une syntaxe moins détaillée:

/path/to/*:somenode
16

Vous pouvez utiliser Namespace = false sur un XmlTextReader

[TestMethod]
public void MyTestMethod()
{
    string _withXmlns = @"<?xml version=""1.0"" encoding=""utf-8""?>
<ParentTag xmlns=""http://anyNamespace.com"">
<Identification value=""ID123456"" />
</ParentTag>
";

    var xmlReader = new XmlTextReader(new MemoryStream(Encoding.Default.GetBytes(_withXmlns)));

    xmlReader.Namespaces = false;

    var content = XElement.Load(xmlReader);

    XElement elem = content.XPathSelectElement("/Identification");

    elem.Should().NotBeNull();
    elem.Attribute("value").Value.Should().Be("ID123456");
}

avec :

using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
1
Pierre Vonderscher

Je ne suis pas autorisé à commenter (!!), je pourrais donc les laisser me faire taire ou ajouter mes deux centimes de toute façon avec une "réponse à un commentaire" ...

J'ai trouvé que ce hack avait un autre inconvénient: cela ne fonctionnait pas si le document déclarait un préfixe d'espace de nom XML (les deux points ne sont pas légaux dans les noms XML, et avec Namespaces == false, le lecteur interprète les points comme faisant partie du nom). , par exemple.

<ParentTag xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
xmlns="http://anyNamespace.com">
0
Dojo