如何为逗号分隔的节点

时间:2017-02-26 01:04:29

标签: xml xslt recursion xslt-1.0

我对如何编写下面的递归循环感到困惑。尝试逗号分隔但看起来像循环只会起作用。任何解决方案,想法都会有所帮助?谢谢我使用的是XML版本1.下面只是一个例子。

我的XML来源:

<Groceries>
    <fruit>Apple,Banana,Peach,Lemon</fruit>
</Groceries>

我正在寻找一个XSLT来获得下面的输出。
所以我想要的XML输出应该是这样的:

<Foods>
      <Food raw="Lemon" cat="Fruit" val="Lemon"/>
      <Food raw="Apple" cat="Fruit" val="Apple"/>
      <Food raw="Peach" cat="Fruit" val="Peach"/>
      <Food raw="Banana" cat="Fruit" val="Banana"/>
</Foods>

我尝试创建XSLT解决方案是:

<xsl:element name="Fruit">
  <xsl:attribute name="raw">
    <xsl:value-of select="substring-before(fruit,',')"/>
  </xsl:attribute>
  <xsl:attribute name="cat">Fruit</xsl:attribute>
  <xsl:attribute name="val">
    <xsl:value-of select="substring-before(fruit,',')"/>
  </xsl:attribute>
</xsl:element>
<xsl:text>&#xa;</xsl:text>
<xsl:element name="Fruit">
  <xsl:attribute name="raw">
    <xsl:value-of select="substring-after(fruit,',')"/>
  </xsl:attribute>
  <xsl:attribute name="cat">Fruit</xsl:attribute>
  <xsl:attribute name="val">
    <xsl:value-of select="substring- after(fruit,',')"/>
  </xsl:attribute>
</xsl:element>
<xsl:text>&#xa;</xsl:text>

由于

2 个答案:

答案 0 :(得分:0)

带有递归模板的XSLT-1.0实现了预期的结果:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="/Groceries">
      <Foods>
        <xsl:call-template name="fruit">           <!-- call the recursive template -->
          <xsl:with-param name="txt" select="concat(fruit/text(),',')" />  <!-- add a leading ',' to make the recursive template behave properly -->
        </xsl:call-template>
      </Foods>
    </xsl:template>

    <xsl:template name="fruit">
      <xsl:param name="txt" />
      <xsl:if test="$txt != ''">
        <xsl:variable name="x" select="normalize-space(substring-before($txt,','))"/>
        <Food raw="{$x}" cat="Fruit" val="{$x}" />  <!-- add 'Food' element with attributes -->
        <xsl:call-template name="fruit">            <!-- call the recursive template with the rest of the comma-separated-string -->
          <xsl:with-param name="txt" select="normalize-space(substring-after($txt,','))" />
        </xsl:call-template>
      </xsl:if>
    </xsl:template>

</xsl:stylesheet>

其输出符合要求:

<?xml version="1.0"?>
<Foods>
    <Food raw="Apple" cat="Fruit" val="Apple"/>
    <Food raw="Banana" cat="Fruit" val="Banana"/>
    <Food raw="Peach" cat="Fruit" val="Peach"/>
    <Food raw="Lemon" cat="Fruit" val="Lemon"/>
</Foods>

答案 1 :(得分:0)

通过为template元素提供名称,让它在满足某些条件时调用自身,并使用call-template元素在内容上调用它来构建递归模板。您的尝试完全没有尝试,因为它不包含任何templatecall-template元素,并且不是有效的XSLT样式表。

此代码将递归地生成所描述的输出,包括所描述的输出元素的看似随机顺序。

<transform xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <output media-type="application/xml"/>
    <template name="parse.CSV.string">
        <param name="CSV.string.element"/>
        <param name="CSV.string" select="string($CSV.string.element/child::text())"/>
        <param name="required.item.string" select="string($CSV.string.element/child::text())"/>
        <variable name="item.string">
            <choose>
                <when test="contains($CSV.string, ',')">
                    <value-of select="substring-before($CSV.string, ',')"/>
                </when>
                <otherwise>
                    <value-of select="$CSV.string"/>
                </otherwise>
            </choose>
        </variable>
        <choose>
            <when test="$item.string = $required.item.string">
                <element name="Food">
                    <attribute name="raw">
                        <value-of select="$item.string"/>
                    </attribute>
                    <attribute name="cat">Fruit</attribute>
                    <attribute name="val">
                        <value-of select="$item.string"/>
                    </attribute>
                </element>
            </when>
            <when test="contains($CSV.string, ',')">
                <call-template name="parse.CSV.string">
                    <with-param name="CSV.string.element" select="$CSV.string.element"/>
                    <with-param name="CSV.string" select="substring-after($CSV.string, ',')"/>
                    <with-param name="required.item.string" select="$required.item.string"/>
                </call-template>
            </when>
        </choose>
    </template>
    <template match="/child::Groceries">
        <element name="Foods">
            <call-template name="parse.CSV.string">
                <with-param name="CSV.string.element" select="child::fruit"/>
                <with-param name="required.item.string" select="'Lemon'"/>
            </call-template>
            <call-template name="parse.CSV.string">
                <with-param name="CSV.string.element" select="child::fruit"/>
                <with-param name="required.item.string" select="'Apple'"/>
            </call-template>
            <call-template name="parse.CSV.string">
                <with-param name="CSV.string.element" select="child::fruit"/>
                <with-param name="required.item.string" select="'Peach'"/>
            </call-template>
            <call-template name="parse.CSV.string">
                <with-param name="CSV.string.element" select="child::fruit"/>
                <with-param name="required.item.string" select="'Banana'"/>
            </call-template>
        </element>
    </template>
</transform>