Search code examples
xmlxsltforeachdspace

XSLT - Group foreach values inside new parent


I'm learning XSLT 1.0 and I have a little problem of logic and knowledge too. I am working with dspace 6, and I want to change the output for some xslt lines code.

When I retrieve some metadata with:

<xsl:for-each select="doc:metadata/doc:element[@name='dc']/doc:element[@name='date']/doc:element[@name='dateType']/doc:element/doc:field[@name='value']">    
    <creator><xsl:value-of select="." /></creator>    
</xsl:for-each>

I get:

<creator>Pavel Hitch</creator>
<creator>Adan Riviera</creator>

What I want to do is that looks like this:

<creators>
    <creator>Pavel Hitch</creator>
    <creator>Adan Riviera</creator>
</creators>

Edit: My problem is when I get just one value, put the "creator tag" only, but with two o more values returned, add the "creators" parent.

I tried save the "foreach" output into a variable, use position() and last() to make some conditionals but the "creators" tag just repet itself (thanks to te foreach), trying this give me some close tag error:

xsl:for-each select="doc:metadata/doc:element[@name='dc']/doc:element[@name='date']/doc:element[@name='dateType']/doc:element/doc:field[@name='value']">
<xsl:variable name="lastPos" select="last()"/>
<xsl:variable name="initPos" select="position()"/>      

<xsl:if test="$lastPos>'1' and $initPos='1' ">
    <Creators>
</xsl:if>
    <creator><xsl:value-of select="." /></creator>
<xsl:if test="$lastPos = $initPos">
    </Creators>
</xsl:if>
</xsl:for-each>

I hope you can help me, I'm really newbie.

Thank you! :)


Solution

  • The problem is that the <creators> tag/element belongs outside of the for-each loop to surround it when there is more than one element.

    when I get just one value, put the "creator tag" only, but with two o more values returned, add the "creators" parent.

    So this can be solved using an xsl:choose which counts the elements to differ between these two cases:

    <xsl:choose>
      <xsl:when test="count(doc:metadata/doc:element[@name='dc']/doc:element[@name='date']/doc:element[@name='dateType']/doc:element/doc:field[@name='value']) > 1">
        <creators>
          <xsl:for-each select="doc:metadata/doc:element[@name='dc']/doc:element[@name='date']/doc:element[@name='dateType']/doc:element/doc:field[@name='value']">    
            <creator><xsl:value-of select="." /></creator>    
          </xsl:for-each>
        </creators>
      </xsl:when>
      <xsl:otherwise>
        <xsl:for-each select="doc:metadata/doc:element[@name='dc']/doc:element[@name='date']/doc:element[@name='dateType']/doc:element/doc:field[@name='value']">    
          <creator><xsl:value-of select="." /></creator>    
        </xsl:for-each>      
      </xsl:otherwise>      
    </xsl:choose>
    

    The xsl:for-each in the second case may be superfluous, but it takes care of the (theoretical) possibility that there are no creators.