You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Saxon免费解析器中如何正确提取指定节点的属性值?

问题:使用Saxon免费解析器处理XML时,如何仅返回属性值?

我正在使用Saxon免费解析器处理XML文件,XML片段如下:

<osmChange>
  <modify>
    <node id="28377390">
      <tag k="name" v="Holywell"/>
      <tag k="public_transport" v="station"/>
      <tag k="railway" v="station"/>
    </node>
        <node id="168325631">
      <tag k="name" v="Whitecraigs"/>
      <tag k="public_transport" v="station"/>
      <tag k="railway" v="station"/>
    </node>
  </modify>
</osmChange>

使用以下XPath可以选中目标<tag>节点:

<xsl:sequence select="$OSM_OSC/osmChange/modify/(node|way)[tag[@k='railway'][@v='station']]/tag[@k='name']"/>

得到结果:

<tag k="name" v="Whitecraigs"/>
<tag k="name" v="Holywell"/>

我希望仅返回属性v的值,即:

Whitecraigs
Holywell

尝试在XPath末尾添加/@v,修改后的代码如下:

<xsl:sequence select="$OSM_OSC/osmChange/modify/(node|way)[tag[@k='railway'][@v='station']]/tag[@k='name']/@v"/>

但出现错误:

java.lang.UnsupportedOperationException: copy() applied to attribute node
at net.sf.saxon.tree.tiny.TinyAttributeImpl.copy(TinyAttributeImpl.java:259)
at net.sf.saxon.serialize.UncommittedSerializer.append(UncommittedSerializer.java:207)
at net.sf.saxon.event.ProxyReceiver.append(ProxyReceiver.java:200)
at net.sf.saxon.serialize.PrincipalOutputGatekeeper.append(PrincipalOutputGatekeeper.java:101)

请问如何正确实现仅返回属性值的需求?


解决方案

这个错误的核心原因是:<xsl:sequence>尝试直接输出属性节点,但XML属性无法脱离父元素单独存在,序列化器在复制属性节点时会触发异常。要解决问题,需要提取属性的字符串值,而非输出属性节点本身。

以下是两种可靠的实现方式:

1. 使用string()函数提取属性值

修改XPath,用string()包裹属性节点,直接获取其字符串值:

<xsl:sequence select="string($OSM_OSC/osmChange/modify/(node|way)[tag[@k='railway'][@v='station']]/tag[@k='name']/@v)"/>

如果需要匹配多个节点并逐个输出值,可配合for-each循环:

<xsl:for-each select="$OSM_OSC/osmChange/modify/(node|way)[tag[@k='railway'][@v='station']]/tag[@k='name']/@v">
  <xsl:sequence select="string(.)"/>
</xsl:for-each>

2. 使用<xsl:value-of>代替<xsl:sequence>

<xsl:value-of>会自动提取节点的字符串值,适合直接输出文本内容,还能通过separator指定值之间的分隔符:

<xsl:value-of select="$OSM_OSC/osmChange/modify/(node|way)[tag[@k='railway'][@v='station']]/tag[@k='name']/@v" separator="&#10;"/>

其中separator="&#10;"用来设置换行符,确保输出结果为每行一个属性值,完全符合预期格式。

补充:XPath 2.0+可用data()函数

如果使用的是XPath 2.0及以上版本,也可以用data()函数,它专门用于提取原子值,效果与string()类似:

<xsl:sequence select="data($OSM_OSC/osmChange/modify/(node|way)[tag[@k='railway'][@v='station']]/tag[@k='name']/@v)"/>

内容的提问来源于stack exchange,提问作者DaveF

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 21:43:21