匹配XSLT上的属性而不是匹配整个元素

时间:2015-02-03 16:36:39

标签: xml xslt xpath xslt-2.0

我想编写一个匹配属性而不是节点的XSL模板,

我认为有这样的事情:

<xsl:template match="@href | @conref | @conrefend">
    <xsl:message select="."/>
</xsl:template>

将匹配这3个属性名称中的任何一个并打印以控制属性的值,因为范围是属性本身而不是节点。

但我的测试证明我错了,我只能匹配包含以下任何属性的节点:

 <xsl:template match="*[@href or @conref or @conrefend]">
   <xsl:message select="if(not(@href)) 
                        then    
                          if(not(@conref)) 
                          then @conrefend 
                          else @conref 
                        else @href"/>  
   </xsl:template>

这种方法的问题在于,如果碰巧存在一个具有多个属性的节点,那么只有一个被处理,我需要全部处理它们。

为什么第一种方法不起作用的任何想法?

EDIT1: 完整的xslt:

  <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      exclude-result-prefixes="xs"
      version="2.0">

     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>             
     <xsl:template match="@conref|@conrefend|@href">
        <xsl:message select="."/>
     </xsl:template>
   </xsl:stylesheet>

测试XML:

  <links>
      <image conref="COPY-GUID/*+-862416}39-37CD-4CF7-A7AA-F09F4A763944" />
   </links>

现在XSLT没有匹配任何内容。

3 个答案:

答案 0 :(得分:1)

您确实可以像第一个模板那样匹配模板中的属性。别的一定是错的......

看一下身份变换:

<xsl:template match="@* | node()">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
</xsl:template>

它可以很好地匹配您正在进行的替代方案,其中一个替代方案适用于所有属性(@*)。

现在考虑xsl:apply-templates语句。请注意如何显式调出@*。您确定要为模板提供应用属性的机会吗?如果你打电话,xsl:apply-templates就是这样,例如:

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

意识到只会选择元素,而不是属性。另请注意,node()也不包含属性。

更新

右。您的属性匹配模板永远不会有机会申请。

添加上面的身份模板,或类似的内容:

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

为您的属性匹配模板提供申请机会。

答案 1 :(得分:1)

默认情况下,XSLT不会查找与属性节点匹配的模板。将模板明确应用于输入XML中的所有属性。

顺便问一下,您确定要使用xsl:message吗? xsl:message的内容不包含在转换输出中。你的意思是xsl:value-of?此外,如果输出文本,则应将输出方法声明为文本。

<强>样式表

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

    <xsl:output method="text"/>
    <xsl:strip-space elements="*"/>

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

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

</xsl:stylesheet>

文字输出

COPY-GUID/*+-862416}39-37CD-4CF7-A7AA-F09F4A763944

实际上,在这个非常简单的情况下,第一个模板就足以获得相同的输出:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

    <xsl:output method="text"/>
    <xsl:strip-space elements="*"/>

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

</xsl:stylesheet>

这是因为,一旦模板应用于属性节点,就会有一个内置模板默认输出其字符串值。

答案 2 :(得分:1)

您当前的方法存在的问题是,从不应用与属性匹配的模板。它没有被应用,因为内置模板规则仅匹配根节点和元素节点,并且它仅将模板应用于子节点节点。要将模板应用于属性,您必须自己明确地应用它。

http://www.w3.org/TR/xslt20/#built-in-rule