2

I am building a blogging website for a school project. A blog post's content consists of a number of elements, each of which can either be plain text, links, images, or videos. All these elements must be shown in the order which they are stored with in the XML file, and each one will be displayed in a new <p> tag.

Hence, the idea is to somehow loop all these elements, and each iteration should perform an `xsl:choose to decide how to display the current iteration's element.

Take this code for example: how can I make it perform only the TEXT part when the element is a b:blogPostContent/b:blogPostText type, and the LINK part when the element is a b:blogPostContent/b:blogPostLink?

<xsl:for-each select="b:blogPostContent/*">
    <p>

        <!--TEXT-->
        <xsl:value-of select="."/>

        <!--LINK-->
        <xsl:element name="a">
            <xsl:attribute name="href">
                <xsl:value-of select="./@target"/>
            </xsl:attribute>
            <xsl:attribute name="target">
                _blank
            </xsl:attribute>
            <xsl:value-of select="."/>
        </xsl:element>

    </p>
</xsl:for-each> 
1

2 Answers 2

1

Use a choose element like this:

<xsl:choose>
  <xsl:when test="name() = 'b:blogPostText'">
    <xsl:value-of select="."/>
  </xsl:when>
  <xsl:otherwise>
    <xsl:element name="a">
        <xsl:attribute name="href">
            <xsl:value-of select="./@target"/>
        </xsl:attribute>
        <xsl:attribute name="target">_blank</xsl:attribute>
        <xsl:value-of select="."/>
    </xsl:element>
  </xsl:otherwise>
</xsl:choose>

Another possiblity is to match those elements in separate templates. Let's say your template matches the b:blogPostContent element (actually, you did not show the structure of your input XML):

<xsl:template match="b:blogPostContent">
   <p>
     <xsl:apply-templates select="b:blogPostText|b:blogPostLink"/>
   </p> 
</xsl:template>

<xsl:template match="b:blogPostText">
  <xsl:value-of select="."/>
</xsl:template>

<xsl:template match="b:blogPostLink">
  <a>
     <xsl:attribute name="href">
         <xsl:value-of select="./@target"/>
     </xsl:attribute>
     <xsl:attribute name="target">_blank</xsl:attribute>
     <xsl:value-of select="."/>
  </a>
</xsl:template>

Note that <xsl:element name="a"> is exactly the same as <a>. That is why I have shortened the notation. (It was inconsistent anyway, since you did not write <xsl:element name="p">).

Sign up to request clarification or add additional context in comments.

1 Comment

Definitely use separate templates
1

Hence, the idea is to somehow loop all these elements, and each iteration should perform an xsl:choose to decide how to display the current iteration's element.

The idea is not bad, but driven by an imperative thought pattern. XSLT is not an imperative language and most of the time it's better to follow declarative patterns.

<xsl:template match="b:blogPostContent">
  <article>
    <xsl:apply-templates select="*" mode="wrap_p" />
  </article>
</xsl:template>

<xsl:template select="*" mode="wrap_p">
  <p>
    <xsl:apply-templates select="." />
  </p>
</xsl:template>

<xsl:template match="b:blogPostText">
  <xsl:value-of select="." />
</xsl:template>

<xsl:template match="b:blogPostLink">
  <a href="{@target}" target="_blank">
    <xsl:value-of select="."/>
  </a>
</xsl:template>

<xsl:template match="b:blogPostList">
  <ul>
    <xsl:apply-templates select="*" />
  </ul>
</xsl:template>

and so on.

This way you get small, dedicated, modular templates that do one thing and one thing only, while the XSLT engine decides which template serves best for which input node.


Note that you never have to write <xsl:element> or <xsl:attribute> unless you want to create them dynamically (names based on variables, for example). If you want an <a> in the output, just put an <a> in the XSLT.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.