cómo ignorar los espacios de nombres con XPath


111

Mi objetivo es extraer ciertos nodos de múltiples archivos xml con múltiples espacios de nombres usando XPath. Todo funciona bien siempre que sepa los URI del espacio de nombres. El nombre del espacio de nombres en sí permanece constante, pero los esquemas (XSD) a veces son generados por el cliente, es decir, desconocidos para mí. Entonces me quedan básicamente tres opciones:

  1. use solo un esquema para el espacio de nombres, esperando que nada salga mal (¿puedo estar seguro?)

  2. obtenga los nodos secundarios del documento y busque el primer nodo con un URI de espacio de nombres, esperando que esté allí y solo use el URI, esperando que sea el correcto. puede salir mal por varias razones

  3. de alguna manera dile a xpath: "mira, no me preocupan los espacios de nombres, solo encuentra TODOS los nodos con este nombre, incluso puedo decirte el nombre del espacio de nombres, pero no el URI". Y esta es la pregunta aquí ...

Esta no es una reiteración de numerosas preguntas de "mi expresión xpath no funciona porque no estoy al tanto de la conciencia del espacio de nombres" como se encuentran aquí o aquí . Sé cómo utilizar el conocimiento del espacio de nombres. Simplemente no cómo deshacerse de él.


2
Si no conoce los esquemas, ¿cómo sabe qué elementos desea?
Paul Butcher


1
gracias por señalar, Alejandro. La búsqueda de "ignorar el espacio de nombres xpath" debería haber revelado este, pero no lo hizo
kostja

2
@kostja: No busques con el cuadro de búsqueda SO, es inútil ... Prueba Google la próxima vez. De hecho, el equipo de SO lo alienta.

1
Google Sitesearch realmente hace un mejor trabajo para encontrar cosas útiles en SO. Me pregunto por qué no es una opción predeterminada. Gracias de nuevo, Alejandro
kostja

Respuestas:


164

Puede utilizar la local-name()función XPath. En lugar de seleccionar un nodo como

/path/to/x:somenode

puede seleccionar todos los nodos y filtrar por el que tenga el nombre local correcto:

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

9
También puede usar local-name()para referirse a los atributos, sin tener en cuenta el espacio de nombres, consulte: stackoverflow.com/q/21239181/274677
Marcus Junius Brutus


1
Tan sencillo. salvó mi tarde.
C Johnson


2

Puede usar Namespace = false en 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");
}

con :

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;

Para seleccionar un nodo a través de XPath, esto funciona; Lamentablemente, no puede guardar el documento debido a un 'The 'xmlns' attribute is bound to the reserved namespaceerror.
AutomatedChaos

2

O puede usar name ():

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

O solo buscar atributos:

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

Si abre el xml como un objeto de PowerShell, ignora los espacios de nombres:

[xml]$xml = get-content file.xml
$xml.path.to.somenode

0

Es mi ejemplo en Qt C ++. Qt es compatible con 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();

Salida del programa: "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>
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.