come ignorare gli spazi dei nomi con XPath


111

Il mio obiettivo è estrarre determinati nodi da più file xml con più spazi dei nomi utilizzando XPath. Tutto funziona bene finché conosco gli URI dello spazio dei nomi. Il nome dello spazio dei nomi stesso rimane costante, ma gli schemi (XSD) a volte sono generati dal client, cioè a me sconosciuti. Quindi mi rimangono fondamentalmente tre scelte:

  1. usa solo uno schema per lo spazio dei nomi, sperando che nulla vada storto (posso esserne sicuro?)

  2. prendi i nodi figli del documento e cerca il primo nodo con un URI dello spazio dei nomi, sperando che sia lì e usa semplicemente l'URI, sperando che sia quello corretto. può andare storto per diversi motivi

  3. in qualche modo dì a xpath: "guarda, non mi interessa degli spazi dei nomi, trova solo TUTTI i nodi con questo nome, posso anche dirti il ​​nome dello spazio dei nomi, ma non l'URI". E questa è la domanda qui ...

Questa non è una ripetizione di numerose domande "la mia espressione xpath non funziona perché non sono a conoscenza della consapevolezza dello spazio dei nomi" come si trovano qui o qui . So come usare la consapevolezza dello spazio dei nomi. Non solo come sbarazzarsene.


2
Se non conosci gli schemi, come fai a sapere quali elementi vuoi?
Paul Butcher

4

1
grazie per la segnalazione, Alejandro. La ricerca di "ignore namespace xpath" avrebbe dovuto rivelare questo, ma non lo ha fatto
kostja

2
@kostja: non cercare con la casella di ricerca SO, è inutile ... Prova Google la prossima volta. In effetti, questo è incoraggiato dal team SO.

1
Google Sitesearch fa effettivamente un lavoro migliore nel trovare cose utili su SO. Mi chiedo perché non sia un'opzione predefinita. Grazie ancora, Alejandro
kostja

Risposte:


164

È possibile utilizzare la local-name()funzione XPath. Invece di selezionare un nodo come

/path/to/x:somenode

puoi selezionare tutti i nodi e filtrare per quello con il nome locale corretto:

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

9
Puoi anche usare anche local-name()per fare riferimento agli attributi, in modo inconsapevole dello spazio dei nomi, vedi: stackoverflow.com/q/21239181/274677
Marcus Junius Brutus


1
Così semplice. mi ha salvato il pomeriggio.
C Johnson


2

È possibile utilizzare Namespace = false su 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;

Per selezionare un nodo tramite XPath, funziona; Purtroppo non sei in grado di salvare il documento a causa di un 'The 'xmlns' attribute is bound to the reserved namespaceerrore.
AutomatedChaos

2

Oppure puoi usare name ():

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

Oppure cerca solo attributi:

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

Se apri xml come oggetto PowerShell, ignora gli spazi dei nomi:

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

0

È il mio esempio in Qt C ++. Qt supporta 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();

Uscita programma: "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>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.