【问题标题】:xsl:apply-template to only nodes with specific attribute valuexsl:apply-template 仅应用于具有特定属性值的节点
【发布时间】:2011-04-01 09:32:28
【问题描述】:

我有一个受 XSLT 约束的 XML 文档。结构类似于:

<root>
  <item value="1">
     <object/>
  </item>
  <item value="2" />
     <object/>
  </item>
</root>

我的目标是最终得到一个转换后的 XML,类似于:

<root>
 <parent>
  <object-one value-one="1"/>
 </parent>
 <parent>
  <object-two value-two="2"/>
 </parent>
</root>

我的 XSLT 类似于:

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


<xsl:template match="object">
    <xsl:call-template name="1" />
    <xsl:call-template name="2" />
</xsl:template>

<xsl:template name="1" match="object[item/@value = '1'">
  <xsl:element name="object-one" namespace="http://something.org">
    <xsl:attribute name="_Description">
      <xsl:value-of select="@_Type"/>
    </xsl:attribute>
    <xsl:attribute name="_Type">
      <xsl:value-of select="@_Amount"/>
   </xsl:attribute>
  </xsl:element>
</xsl:template>

 <xsl:template name="2" match="object[item/@value = '2'">
  <xsl:element name="object-two" namespace="http://something.org">
    <xsl:attribute name="OriginalAmount">
      <xsl:value-of select="@_Amount"/>
    </xsl:attribute>
  </xsl:element>
</xsl:template>

问题是所有项目节点都应用了相同的模板。如何将模板仅应用于特定节点?

【问题讨论】:

    标签: xslt transform


    【解决方案1】:

    编辑:现在针对不同的输入样本(针对格式正确进行了校正):

    <root>
        <item value="1">
            <object/>
        </item>
        <item value="2" >
            <object/>
        </item>
    </root>
    

    这个样式表:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:num="number" extension-element-prefixes="num">
        <num:num>one</num:num>
        <num:num>two</num:num>
        <xsl:template match="root">
            <xsl:copy>
                <xsl:apply-templates/>
            </xsl:copy>
        </xsl:template>
        <xsl:template match="item">
            <parent>
                <xsl:apply-templates/>
            </parent>
        </xsl:template>
        <xsl:template match="object">
            <xsl:variable name="vTextNumber" select="document('')/*/num:*[number(current()/../@value)]"/>
            <xsl:element name="object-{$vTextNumber}">
                <xsl:attribute name="value-{$vTextNumber}">
                    <xsl:value-of select="../@value"/>
                </xsl:attribute>
            </xsl:element>
        </xsl:template>
    </xsl:stylesheet>
    

    输出:

    <root>
        <parent>
            <object-one value-one="1" />
        </parent>
        <parent>
            <object-two value-two="2" />
        </parent>
    </root>
    

    编辑 2:现在,您的样式表片段有什么问题?好吧,您似乎不知道处理器如何解析应用的模板规则,以及 XPath 导航。

    首先,object[item/@value = '1'] 将只匹配这种输入

    <object>
        <item value="1"/>
    </object>
    

    其次,考虑这三个规则

    1 -

    <xsl:template match="object">
    </xsl:template> 
    

    2 -

    <xsl:template name="1" match="object[../@value = '1']"> 
    </xsl:template> 
    

    3 -

    <xsl:template name="2" match="object[../@value = '2']"> 
    </xsl:template> 
    

    使用您最后提供的输入,第一个 object 元素(按文档顺序)将匹配规则 1 和 2,然后处理器将解析应用规则 2。为什么?来自http://www.w3.org/TR/xslt#conflict

    接下来,所有匹配的模板规则 比匹配的优先级低 模板规则或规则与 最高优先级被淘汰 考虑。 a的优先级 模板规则由 模板上的优先级属性 规则。这个值必须是真实的 数字(正或负), 将生产编号与 可选的前导减号 (-)。这 默认优先级计算为 如下:

    • 如果模式包含多个由 | 分隔的备选方案,则它
      等同于一组模板规则,每个规则一个
      替代方案。
    • 如果模式是 QName 的形式,前面有 a
      ChildOrAttributeAxisSpecifier 或具有形式 processing-instruction(Literal)
      前面有 ChildOrAttributeAxisSpecifier,则优先级为 0。
    • 如果模式的格式为 NCName:*,前面有 a
      ChildOrAttributeAxisSpecifier,则优先级为-0.25。
    • 否则,如果模式仅包含一个 NodeTest 前面有 ChildOrAttributeAxisSpecifier,则优先级为 -0.5。
    • 否则,优先级为 0.5。

    【讨论】:

    • 我尝试了您的建议,但无法获得所需的结果。它只对每个 应用两个模板中的一个,而目标是应用两个模板,但仅在条件匹配的地方应用。请使用更准确的代码查看我修改后的问题。
    • 我遇到的主要问题是我要测试的值属于我应用模板的节点的父节点。
    • @alan: I tried your suggestions but I was unable to get the desired results 好吧,你已经改变了输入和期望的输出!最好的做法是问另一个问题。否则,您应该将这些新闻添加到您的问题中,而不是替换。看看我的编辑。如果我自己的样式表中有什么不清楚的地方,请具体询问。
    • @Alejandro:对不起,如果我不清楚,元素名称是任意的,我不想将值转换为名称的一部分。问题是我需要测试 元素的值;基于 @value 我需要将两个模板之一应用于 元素,这两个模板(虽然基于 )将导致不同的元素名称。
    • @alan:没有通用的解决方案。在声明性范例中,您必须将特定输入映射到特定输出(或至少使用众所周知的模式)。所以,我只能向你解释你自己的模板有什么问题。查看我的编辑。
    【解决方案2】:

    也许你可以让你的匹配更具体:

    <xsl:template name="item1" match="item[@value=1]">
        <xsl:element name="item" namespace="http://something.org">
            <xsl:attribute name="_Description">
                <xsl:value-of select="@_Type"/>
            </xsl:attribute>
            <xsl:attribute name="_Type">
                <xsl:value-of select="@_Amount"/>
            </xsl:attribute>
        </xsl:element>
    </xsl:template>
    
    <xsl:template name="item2" match="item[@value=2]">
        <xsl:element name="item2_item" namespace="http://something.org">
            <xsl:attribute name="OriginalAmount">
                <xsl:value-of select="@_Amount"/>
            </xsl:attribute>
        </xsl:element>
    </xsl:template>
    

    【讨论】:

    • 感谢您的建议,我已尝试实施您的建议,但我仍然只将一个模板应用于所有 节点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-31
    • 1970-01-01
    • 1970-01-01
    • 2013-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多