使用XSL转换标签序列

时间:2010-01-20 12:19:18

标签: xml xslt if-statement foreach

我很擅长使用XSL。我正在尝试使用XSL将XML文件转换为具有不同结构的另一个XML文件。 XML的输入部分如下所示:

<tag>
    <Keyword>Event: Some Text</Keyword>
    <Keyword>Group: Some Text</Keyword>
    <Keyword>Other: Some Text</Keyword>
</tag>

我希望输出为:

<tag>
    <event> Some Text </event>
    <group> Some Text </group>
    <other> Some Text </other>
</tag>

我的当前XSL 文件:

<xsl:for-each select="tag">
    <xsl:if test="starts-with(Keyword, 'Event: ')">
        <event>
          <xsl:value-of select="substring-after(Keyword, 'Event: ')"/>
        </event>
    </xsl:if>
    <xsl:if test="starts-with(Keyword, 'Group: ')">
        <group>
          <xsl:value-of select="substring-after(Keyword, 'Group: ')"/>
        </group>
    </xsl:if>
    <xsl:if test="starts-with(Keyword, 'Other: ')">
        <other>
          <xsl:value-of select="substring-after(Keyword, 'Other: ')"/>
        </other>
    </xsl:if>
</xsl:for-each>

当前输出仅显示事件节点,不显示其余节点:

<tag>
    <event> Some Text </event>
</tag>

我尝试在XSL中使用'event'部分切换'group'部分,但是由于输入XML中关键字节点的排序,所有子节点都没有显示。那么我如何阅读所有关键字节点并将它们转换为相应的新节点进行显示?

3 个答案:

答案 0 :(得分:3)

@Pierre:我理解初始问题和你的解决方案;) 你的方式为XML元素构建恕我直言 hackly 。 XSLT具有用于动态构造xml元素的特殊集。因此,模板匹配=“关键字”可能如下所示

<xsl:template match="Keyword">
  <xsl:variable name="tag" select="normalize-space(substring-before(.,':'))"/>
  <xsl:element name="{$tag}">
    <xsl:value-of select="normalize-space(substring-after(.,':'))"/>
  </xsl:element>
</xsl:template>

因此,如果需要,您可以选择轻松地将属性添加到输出XML元素,并且不会因禁用输出转义等而烦恼。

答案 1 :(得分:2)

您只有一个tag元素。你想迭代所有孩子

<xsl:for-each select="tag/*">

    <xsl:if test="starts-with(., 'Event: ')">
        <event>
          <xsl:value-of select="substring-after(., 'Event: ')"/>
        </event>
    </xsl:if>
    <xsl:if test="starts-with(., 'Group: ')">
        <group>
          <xsl:value-of select="substring-after(., 'Group: ')"/>
        </group>
    </xsl:if>
    <xsl:if test="starts-with(., 'Other: ')">
        <other>
          <xsl:value-of select="substring-after(., 'Other: ')"/>
        </other>
    </xsl:if>
</xsl:for-each>

编辑:添加了另一种解决方案(使用@Pierre的原始解决方案) 注意 xsl:element name属性的值包含在{}中,以便将其评估为Attribute Value Template,而非作为文字字符串

<xsl:template match="tag">
<xsl:apply-templates select="Keyword"/>
</xsl:template>

<xsl:template match="Keyword">
<xsl:element name="{normalize-space(substring-before(.,':'))}">
 <xsl:value-of select="normalize-space(substring-after(.,':'))"/>
</xsl:element>
</xsl:template>

答案 2 :(得分:2)

这是我的解决方案。您不必使用 xsl:element

创建所有 if 语句
<xsl:template match="tag">
<xsl:apply-templates select="Keyword"/>
</xsl:template>

<xsl:template match="Keyword">
 <xsl:variable name="tag" select="normalize-space(substring-before(.,':'))"/>
 <xsl:value-of select="concat('&lt;',$tag,'&gt;')" disable-output-escaping="yes"/>
 <xsl:value-of select="normalize-space(substring-after(.,':'))"/>
 <xsl:value-of select="concat('&lt;/',$tag,'&gt;')" disable-output-escaping="yes"/>
</xsl:template>