如何使用 XPath 忽略命名空间
Posted
技术标签:
【中文标题】如何使用 XPath 忽略命名空间【英文标题】:how to ignore namespaces with XPath 【发布时间】:2011-05-25 08:05:08 【问题描述】:我的目标是使用 XPath 从具有多个名称空间的多个 XML 文件中提取某些节点。只要我知道命名空间 URI,一切都可以正常工作。命名空间名称本身保持不变,但模式(XSD)有时是客户端生成的,即我不知道。那么我基本上只有三个选择:
-
只为命名空间使用一个架构,希望不会出错(我可以确定吗?)。
获取文档的子节点并查找具有命名空间 URI 的第一个节点,希望它存在并且只使用 URI,希望它是正确的。这可能会因多种原因出错
不知何故告诉 xpath:“看,我不关心命名空间,只需找到具有此名称的所有节点,我什至可以告诉你命名空间的名称,而不是 URI”。这就是这里的问题...
这不是重复出现在here 或here 中的众多“我的 xpath 表达式不起作用,因为我不知道命名空间意识”问题。我知道如何使用命名空间感知,只是不知道如何摆脱它。
【问题讨论】:
如果你不知道模式,你怎么知道你想要什么元素? How to ignore namespace when parsing XML document with XPath 的完全相同的副本 感谢您指出,亚历杭德罗。搜索“ignore namespace xpath”应该会显示这个,但它没有 @kostja:不要用SO搜索框搜索,没用的……下次试试谷歌。事实上,这是 SO 团队鼓励的。 Google 站点搜索实际上在查找 SO 上的有用内容方面做得更好。我想知道为什么它不是默认选项。再次感谢亚历杭德罗 【参考方案1】:这是我在 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>
【讨论】:
【参考方案2】:或者你可以使用 name():
/path/to/*[name() = 'somenode']
或者只搜索属性:
//*[@attribute="this one"]
如果将 xml 作为 powershell 对象打开,它会忽略命名空间:
[xml]$xml = get-content file.xml
$xml.path.to.somenode
【讨论】:
【参考方案3】:您可以在 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 选择一个节点,这是可行的;很遗憾,由于出现'The 'xmlns' attribute is bound to the reserved namespace
错误,您无法保存文档。【参考方案4】:
您可以在 XPath2.0 中以不那么冗长的语法执行相同的操作:
/path/to/*:somenode
【讨论】:
不过,这不适用于默认命名空间中的元素。【参考方案5】:您可以使用local-name()
XPath 函数。而不是选择像
/path/to/x:somenode
您可以选择所有节点并过滤具有正确本地名称的节点:
/path/to/*[local-name() = 'somenode']
【讨论】:
您也可以使用local-name()
来引用属性,以不知道命名空间的方式,请参阅:***.com/q/21239181/274677
看看这个教程:codesimplify.com/java/java-xpath-ignore-namespace-example
如此简单。拯救了我的下午。
在找到这个问题之前,我花了太多时间试图解决这个问题。谢谢!以上是关于如何使用 XPath 忽略命名空间的主要内容,如果未能解决你的问题,请参考以下文章