comment ignorer les espaces de noms avec XPath

111

Mon objectif est d'extraire certains nœuds de plusieurs fichiers xml avec plusieurs espaces de noms en utilisant 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. Ensuite, il me reste essentiellement trois choix:

  1. utilisez un seul schéma pour l'espace de noms, en espérant que rien ne va pas (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 noms, en espérant qu'il y soit et utilisez simplement l'URI, en espérant que c'est le bon. peut mal tourner pour plusieurs raisons

  3. dites en quelque sorte à xpath: "regardez, je ne me soucie pas des espaces de noms, trouvez juste 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 questions "mon expression xpath ne fonctionne pas parce que je ne suis pas au courant de la connaissance de l'espace de noms" que l'on trouve ici ou ici . Je sais comment utiliser la reconnaissance de l'espace de noms. Mais pas comment s'en débarrasser.

Kostja
la source
2
Si vous ne connaissez pas les schémas, comment savoir quels éléments vous voulez?
Paul Butcher
1
merci de le signaler, Alejandro. La recherche de "ignore namespace xpath" aurait dû révéler celui-ci, mais ce n'est pas le cas
kostja
2
@kostja: Ne cherchez pas avec le champ de recherche SO, c'est inutile ... Essayez Google la prochaine fois. En fait, cela est encouragé par l'équipe SO.
1
Google sitesearch fait en fait un meilleur travail pour trouver des informations utiles sur SO. Je me demande pourquoi ce n'est pas une option par défaut. Merci encore, Alejandro
kostja

Réponses:

165

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

/path/to/x:somenode

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

/path/to/*[local-name() = 'somenode']
Dirk Vollmar
la source
9
Vous pouvez également utiliser le local-name()pour faire référence aux attributs, d'une manière ignorant les espaces de noms, voir: stackoverflow.com/q/21239181/274677
Marcus Junius Brutus
Jetez un œil à ce tutoriel: codesimplify.com/java/java-xpath-ignore-namespace-example
hipokito
1
Si simple. sauvé mon après-midi.
C Johnson
21

Vous pouvez faire la même chose dans XPath2.0 dans une syntaxe moins verbeuse:

/path/to/*:somenode
Andrés Cuadros Suárez
la source
3

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;
Pierre Vonderscher
la source
Pour sélectionner un nœud via XPath, cela fonctionne; Malheureusement, vous ne pouvez pas enregistrer le document en raison d'une 'The 'xmlns' attribute is bound to the reserved namespaceerreur.
AutomatedChaos
2

Ou vous pouvez utiliser name ():

/path/to/*[name() = 'somenode']

Ou uniquement les attributs de recherche:

//*[@attribute="this one"]

Si vous ouvrez le xml en tant qu'objet PowerShell, il ignore les espaces de noms:

[xml]$xml = get-content file.xml
$xml.path.to.somenode
js2010
la source
0

C'est mon exemple en Qt C ++. Qt prend en charge XPath 2.0:

    QString planePath = ":/Models/Plane.dae";
    QFile f(planePath);
    if (!f.open(QIODevice::ReadOnly))
    {
        std::cerr << "Failed to load the file: " <<
                     planePath.toStdString() << std::endl;
        return;
    }

    QXmlQuery query;
    query.bindVariable("myFile", &f);
//    query.setQuery("doc($myFile)//*[local-name() = 'p']/text()"); // it works too but it is XPath 1.0
    query.setQuery("doc($myFile)//*:p/text()");

    QString result;
    query.evaluateTo(&result);
    qDebug() << result;
    f.close();

Sortie programme: "1 0 0 2 0 1 0 0 2 1 0 3 3 0 4 2 0 5\n"

Plane.dae

<?xml version="1.0" encoding="utf-8"?>
<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <asset>
    <contributor>
      <author>Blender User</author>
      <authoring_tool>Blender 2.83.3 commit date:2020-07-22, commit time:06:01, hash:353e5bd7493e</authoring_tool>
    </contributor>
    <created>2020-08-03T14:03:19</created>
    <modified>2020-08-03T14:03:19</modified>
    <unit name="meter" meter="1"/>
    <up_axis>Z_UP</up_axis>
  </asset>
  <library_effects>
    <effect id="PlaneMaterial-effect">
      <profile_COMMON>
        <technique sid="common">
          <lambert>
            <emission>
              <color sid="emission">0 0 0 1</color>
            </emission>
            <diffuse>
              <color sid="diffuse">0.01664001 0.8000001 0.01191879 1</color>
            </diffuse>
            <reflectivity>
              <float sid="specular">0.5</float>
            </reflectivity>
          </lambert>
        </technique>
      </profile_COMMON>
    </effect>
  </library_effects>
  <library_images/>
  <library_materials>
    <material id="PlaneMaterial-material" name="PlaneMaterial">
      <instance_effect url="#PlaneMaterial-effect"/>
    </material>
  </library_materials>
  <library_geometries>
    <geometry id="Plane-mesh" name="Plane">
      <mesh>
        <source id="Plane-mesh-positions">
          <float_array id="Plane-mesh-positions-array" count="12">-1 -1 0 1 -1 0 -1 1 0 1 1 0</float_array>
          <technique_common>
            <accessor source="#Plane-mesh-positions-array" count="4" stride="3">
              <param name="X" type="float"/>
              <param name="Y" type="float"/>
              <param name="Z" type="float"/>
            </accessor>
          </technique_common>
        </source>
        <source id="Plane-mesh-normals">
          <float_array id="Plane-mesh-normals-array" count="3">0 0 1</float_array>
          <technique_common>
            <accessor source="#Plane-mesh-normals-array" count="1" stride="3">
              <param name="X" type="float"/>
              <param name="Y" type="float"/>
              <param name="Z" type="float"/>
            </accessor>
          </technique_common>
        </source>
        <source id="Plane-mesh-map-0">
          <float_array id="Plane-mesh-map-0-array" count="12">1 0 0 1 0 0 1 0 1 1 0 1</float_array>
          <technique_common>
            <accessor source="#Plane-mesh-map-0-array" count="6" stride="2">
              <param name="S" type="float"/>
              <param name="T" type="float"/>
            </accessor>
          </technique_common>
        </source>
        <vertices id="Plane-mesh-vertices">
          <input semantic="POSITION" source="#Plane-mesh-positions"/>
        </vertices>
        <triangles material="PlaneMaterial-material" count="2">
          <input semantic="VERTEX" source="#Plane-mesh-vertices" offset="0"/>
          <input semantic="NORMAL" source="#Plane-mesh-normals" offset="1"/>
          <input semantic="TEXCOORD" source="#Plane-mesh-map-0" offset="2" set="0"/>
          <p>1 0 0 2 0 1 0 0 2 1 0 3 3 0 4 2 0 5</p>
        </triangles>
      </mesh>
    </geometry>
  </library_geometries>
  <library_visual_scenes>
    <visual_scene id="Scene" name="Scene">
      <node id="Plane" name="Plane" type="NODE">
        <matrix sid="transform">1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1</matrix>
        <instance_geometry url="#Plane-mesh" name="Plane">
          <bind_material>
            <technique_common>
              <instance_material symbol="PlaneMaterial-material" target="#PlaneMaterial-material">
                <bind_vertex_input semantic="UVMap" input_semantic="TEXCOORD" input_set="0"/>
              </instance_material>
            </technique_common>
          </bind_material>
        </instance_geometry>
      </node>
    </visual_scene>
  </library_visual_scenes>
  <scene>
    <instance_visual_scene url="#Scene"/>
  </scene>
</COLLADA>
8Observateur8
la source