如何使用XPath忽略命名空间

137
我的目标是使用 XPath 从多个带有不同命名空间的 XML 文件中提取特定的节点。只要我知道命名空间 URI,一切都可以正常工作。命名空间名称本身保持不变,但模式(XSD)有时是由客户端生成的,也就是对我来说未知的。然后我基本上有三个选择:
1. 使用一个模式来表示命名空间,希望不会出错(我能确定吗?)。 2. 获取文档的子节点并查找带有命名空间 URI 的第一个节点,希望它存在并仅使用该 URI,希望它是正确的。这可能由于多种原因而出现问题。 3. 某种方式告诉 XPath:“看,我不在乎命名空间,只要找到所有这个名称的节点,我甚至可以告诉你命名空间的名称,只是不知道 URI”。这就是这里的问题...
这不是无数“我的 XPath 表达式不起作用,因为我不了解命名空间意识”的问题的重复,如这里这里所述。我知道如何使用命名空间意识,只是不知道如何摆脱它。

2
如果你不知道模式,你怎么知道你想要哪些元素呢? - Paul Butcher
4
如何在使用XPath解析XML文档时忽略命名空间?这是一个关于如何使用XPath解析XML文档时忽略命名空间的问题。原问题链接为stackoverflow.com/questions/4402310/how-to-ignore-namespace-when-parsing-xml-document-with-xpath。 - user357812
1
谢谢指出,Alejandro。搜索“ignore namespace xpath”应该会显示出这个结果,但它没有。 - kostja
@Paul Butcher - 我不知道模式的确切URI,但幸运的是模式之间的更改(即一个模式的不同版本)并不影响我正在寻找的节点。 - kostja
2
@kostja:不要使用SO搜索框,它没用...下次试试谷歌。事实上,这是SO团队鼓励的。 - user357812
1
Google站内搜索实际上在查找SO上有用的东西方面做得更好。我想知道为什么它不是默认选项。再次感谢,Alejandro。 - kostja
5个回答

205

您可以使用local-name() XPath函数。与选择节点不同的是

/path/to/x:somenode

你可以选择所有节点,并筛选具有正确本地名称的节点:

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

11
您也可以使用 local-name() 来引用属性,以无命名空间的方式进行操作,详情请参见:https://dev59.com/8nvaa4cB1Zd3GeqPEIXy - Marcus Junius Brutus
请查看此教程:http://www.codesimplify.com/java/java-xpath-ignore-namespace-example/ - hipokito
1
太简单了。救了我的下午。 - C.J.
在找到这个解决方法之前,我花了太多时间来尝试解决这个问题。谢谢! - wolfmason
1
@hipokito的codesimplify链接已经失效。这里是wayback版本:http://web.archive.org/web/20210624020506/http://www.codesimplify.com/java/java-xpath-ignore-namespace-example/ - Kristof Neirynck

30

你可以在XPath2.0中使用更加简洁的语法来完成同样的操作:


/path/to/*:somenode

6
这在默认命名空间中的元素上不起作用。 - Rafael Winterhalter

10

或者您可以使用name():

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

或仅搜索属性:

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

如果您将XML作为PowerShell对象打开,则会忽略命名空间:

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

哎呀,我走了很多地方,走了很多错路。这一个不错。 - Nicholas DiPiazza
也适用于//*[name() = 'somenode'] - Piotr Grudzień

4
您可以在XmlTextReader上使用Namespace = false。
[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");
}

使用:

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;

通过XPath选择节点是可行的;不幸的是,由于“'xmlns'属性绑定到保留的命名空间”错误,您无法保存文档。 - AutomatedChaos

0

这是我在Qt C++中的一个示例。Qt支持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();

程序输出:"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>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接