xsltplonediazo

XSLT/Diazo: create element for each pair of elements


I'm using Diazo/XSLT for theming a Plone website. On the homepage, Plone gives me the following structure:

<dl>
  <dt>
    <a href="...">The news item title</a>
  </dt>
  <dd>
    The content of the news item
  </dd>
  (and so on for the following ones)
</dl>

Which I want to transform into something like that:

<div id="news_items">
  <div>
    <h2><a href="...">The news item title</a></h2>
    The content of the news item.
    <a class="readmore" href="<the HREF taken from the dt/a tag)">Read more</a>
  </div>
  (and so on for the following items)
</div>

I'm not really familiar with XSLT and Diazo (and more used to rewrite some pieces of existing themes) but I tried a few solutions.

The first one was to do this in two times. First look for each "dd" tags, creates the structure and after that update by parsing all "dt" tags:

<copy css:theme="#news_items">
  <xsl:for-each css:select="#content-core dl dd">
    <xsl:element name="div">
      <xsl:element name="h2">
      </xsl:element>
      <xsl:copy-of select="./*" />
      <xsl:element name="a">
        <xsl:attribute name="class">readmore</xsl:attribute>
        Read more
      </xsl:element>
    </xsl:element>
  </xsl:for-each>
</copy>

It creates the structure correctly, but I don't know how to write the second part. The idea would be something like that:

<xsl:for-each css:select="#content-core dl dt">
   <!-- Copy the link in the 'dd' tag into the h2 tag, based on the position --> 
   <copy css:theme="#news_item div:nth-child(position()) h2" css:select="a" />

   <!-- Copy the a tag's href in the 'Read more' tag -->
   <copy css:theme="#news_item div:nth-child(position()) a.readmore">
     <xsl:attribute name="class">
       <xsl:value-of select="@class" />
     </xsl:attribute>
   </copy>
</xsl:for-each>

I know it does not make that much sense, but I hope you get the idea of it:

  1. I look into each "dd" tag

  2. I find, based on the position in the loop, the 'h2' tag created in the previous step and I copy the link inside the "dd" tag.

  3. I find (based on the position again) the "a.readmore" tag and copy the href.

The second solution I've been thinking about is a bit dirtier (and does not work either). The idea is to create the content in one step:

<xsl:for-each css:select="#content-core dl > *">
  <xsl:if test="name = dt">
     <!-- That the dt tag, we start the 'div' tag and add the h2 tag -->
  </xsl:if>

  <xsl:if test="name = dt">
     <!-- That the dt tag, we copy the content and close the 'div' tag -->
  </xsl:if>
</xsl:foreach>

But I really don't like the solution (and I don't see how to create the 'Read more' link).

Do you think the first solution can be done ? (especially the second step to populate the "h2" tag and add the "href" attribute on the "Read more" link). Is there a way better solution available ?

I'd prefer to use only Diazo, but if it's not doable I can directly override the view in Plone (which would be simpler I think, at least I know how to do that)

Thanks for your help.


Solution

  • This transformation:

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
    
     <xsl:template match="/*">
         <div id="news_items">
          <xsl:apply-templates select="dt"/>
         </div>
     </xsl:template>
    
     <xsl:template match="dt">
      <div>
        <h2><xsl:copy-of select="a"/></h2>
        <xsl:apply-templates select="following-sibling::dd[1]"/>
        <a class="readmore" href="{a/@href}">Read more</a>
      </div>
     </xsl:template>
    </xsl:stylesheet>
    

    when applied on the following XML document (with the same structure as the provided one but with more items):

    <dl>
        <dt>
            <a href="someUrl1">The news item1 title</a>
        </dt>
        <dd>
          The content of the news item1
      </dd>
        <dt>
            <a href="someUrl2">The news item2 title</a>
        </dt>
        <dd>
          The content of the news item2
     </dd>
    </dl>
    

    produces the wanted, correct result:

    <div id="news_items">
       <div>
          <h2>
             <a href="someUrl1">The news item1 title</a>
          </h2>
          The content of the news item1
      <a class="readmore" href="someUrl1">Read more</a>
       </div>
       <div>
          <h2>
             <a href="someUrl2">The news item2 title</a>
          </h2>
          The content of the news item2
     <a class="readmore" href="someUrl2">Read more</a>
       </div>
    </div>