【问题标题】:How to find the relative xpath notation from a node to its child node in xslt ?如何在 xslt 中找到从节点到其子节点的相对 xpath 表示法?
【发布时间】:2013-06-12 01:50:04
【问题描述】:

我对 xslt 比较陌生,但是我很幸运地设计了一个巨大的 xml 文件。现在我被困在一个地方,无法继续。可以说xml文件的结构有点像

<xxx>
.......
.......
.......
 <Field id="123" type="fld" elem="3">
   <td:value passed="true"> 25 </td:value>
 </Field>
.......
.......
.......

</xxx>

我目前在 Field 节点。如果我做一个&lt;xsl:value of select="name()" /&gt;,它会给出“字段”,如果我做一个&lt;xsl:value of select="@type" /&gt;,我会得到“fld”。但如果我执行&lt;xsl:value of select="." /&gt;,我会得到&lt;td:value&gt; 内部的值,即25。

我担心的是我需要在 td:value 中获取“通过”属性的值。如果我从当前位置使用以下模板,我可以访问该属性。

<xsl:apply-templates select="*[@passed]" />

  <xsl:template match="*[@passed]" >
       <xsl:value-of select="@passed" />
     </xsl:template>

但问题是“通过”属性可能并不总是存在,所以我需要仅使用节点名称访问 &lt;td:value&gt; 节点。

我试过了

<xsl:apply-templates select=".//td" />
<xsl:apply-templates select=".//td:value" />
<xsl:apply-templates select=".//*" />
<xsl:apply-templates select=".*" />
<xsl:apply-templates select="td" />

似乎没有任何效果。我如何从 Field 节点到达那个 td:value 节点?

【问题讨论】:

  • 您的 XSLT 是否知道 td: 命名空间?
  • 是的,存在一个 xmlns:td="somewebsite" 命名空间声明。

标签: xml xslt xpath


【解决方案1】:

您需要在输入 XML 中声明分配给 td 前缀 td:value 的相同命名空间。例如:

<foo xmlns:td="urn:td">
  <Fieldid="123" type="fld" elem="3">
    <td:value passed="true"> 25 </td:value>
  </Field>
</foo>

XSLT 可能类似于:

<xsl:template match="Field">
  <xsl:if test="td:value@passed" xmlns:td="urn:td">
    <xsl:value-of select="td:value"/>
  </xsl:if>
</xsl:template>

重要的部分是命名空间与输入文档中的相同,如果 XSLT 文档中的前缀名称不同,则无关紧要。如果可能,并且所有 XML 都在您的控制之下,为了清楚起见,它应该是。

【讨论】:

  • Paulo,如果不提及模板中的 xmlns:td,&lt;xsl:value-of select="td:value"/&gt; 会不会工作?是强制性的吗?
  • 专门匹配td:value,是的。您可以在任何包含节点中声明命名空间,例如根 xsl:stylesheet。但是,如果您真的想忽略命名空间,请尝试&lt;xsl:template match="local-name(.) = 'value'"&gt;
【解决方案2】:

澄清一下,您当前位于 field 元素上,并且您正在尝试选择子 td:value 以获取其 @passed 属性,但如果该属性不存在,则要获取获取元素的值。

嗯,你能做的首先是替换这个

<xsl:apply-templates select="*[@passed]" />

只有这个

<xsl:apply-templates select="*" />

然后,您需要两个匹配的模板;一种用于当属性存在时,一种用于捕获其他情况

<xsl:template match="Field/*[@passed]" >
   <xsl:value-of select="@passed" />
</xsl:template>

<xsl:template match="Field/*" >
   <xsl:value-of select="." />
</xsl:template>

当您有两个这样的模板时,XSLT 将首先匹配更具体的一个。因此,如果存在 @passed 属性,则始终匹配第一个模板(即使第二个模板也匹配它)。当没有一个存在时,将使用第二个。

编辑:如果你不想指定元素名称,你可以用这个替换你的模板...

<xsl:template match="*[@passed]" >
   <xsl:value-of select="@passed" />
</xsl:template>

<xsl:template match="*" >
   <xsl:value-of select="." />
</xsl:template>

但是,这些将开始匹配所有可能影响 XSLT 其他部分的元素。因此,您可能必须在此处使用 mode 参数

<xsl:apply-templates select="*" mode="Field" />

<xsl:template match="*[@passed]" mode="Field" >
   <xsl:value-of select="@passed" />
</xsl:template>

<xsl:template match="*" mode="Field" >
   <xsl:value-of select="." />
</xsl:template>

【讨论】:

  • 嘿蒂姆,感谢您的快速回答。我忘了再提一个约束。标签“字段”不一致,可能在每种情况下都不同。那么现在如何引用模板而不是 "Field/*[@passed]" 和 "Field/*" ?
  • 啊,我完全忘记了模式参数。它现在工作正常。非常感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-06
  • 2021-09-05
  • 1970-01-01
  • 2022-01-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多