2

In an attempt to learn more about the possibilities of XSLT I'm wondering if the is a better way to write this conditional code using a different approach.

It simply looks for the href in the first instance and if a href input is present the associated image with a link will display + alt tag output. If no href input is present just the image itself will display + alt tag output.

It works fine for the particular purpose albeit looking and feeling a little clunky.

So I'm wanting to know if there is a cleaner or smarter way of achieving the outcome.

Any advice would be greatly appreciated.

Thanks, ozmo

Anyhoo, here's my master-piece...

      <!-- SUPPORTING IMAGE HREF CONDITIONAL -->
      <xsl:choose>
        <xsl:when test="SupportingImageLink/a/@href !=''">
          <tr>
            <td>
              <a href="{SupportingImageLink/a/@href}">
                <img src="{SupportingImage/img/@src}" width="680" alt="{SupportingImage/img/@alt}" style="border: 0;width: 100%;max-width: 680px;" class="center-on-narrow"></img>
              </a>
            </td>
          </tr>
        </xsl:when>
        <xsl:otherwise>
          <tr>
            <td>
                <img src="{SupportingImage/img/@src}" width="680" alt="{SupportingImage/img/@alt}" style="border: 0;width: 100%;max-width: 680px;" class="center-on-narrow"></img>
            </td>
          </tr>
        </xsl:otherwise>
      </xsl:choose>
      <!-- SUPPORTING IMAGE HREF CONDITIONAL : END -->

And as requested here is the stripped down XML...

<root>
  <Title>New layout test</Title>
  <Edition>Octovember 2019</Edition>
  <Notification>
  <Body>Warning Warning Warning Will Robinson!! Aliens Aliens Aliens everywhere!</Body>
  </Notification>
  <Introduction>
    <Heading>Squids attack!</Heading>
    <Body>Ugh tacos artisan, single-origin coffee jianbing hoodie skateboard. 90's unicorn next level fixie. Glossier coloring book drinking vinegar, health goth flexitarian activated charcoal yuccie hexagon whatever normcore bushwick ethical mustache plaid lyft. Chicharrones edison bulb vinyl disrupt tbh glossier, marfa mumblecore four loko +1 leggings.</Body>
  </Introduction>
  <Section>
    <Heading>Just in - Cyborg bears attacking!</Heading>
    <Structure>3</Structure>
    <SupportingImage>
      <img src="/uploadedImages/dev/robots.png?n=3082" alt="Will Robinson" title="Will Robinson" style="width: 680px; height: 283px;" align="left" width="680" height="283" />
    </SupportingImage>
    <SupportingImageLink>
      <a href="http://www.squids-attack/cyb-bears.html">AAARRRRGGGGHHHH!!!</a>
    </SupportingImageLink>
    <Body>Ugh tacos artisan, single-origin coffee jianbing hoodie skateboard. 90's unicorn next level fixie. Glossier coloring book drinking vinegar, health goth flexitarian activated charcoal yuccie hexagon whatever normcore bushwick ethical mustache plaid lyft. Chicharrones edison bulb vinyl disrupt tbh glossier, marfa mumblecore four loko +1 leggings. Knausgaard af YOLO, direct trade drinking vinegar try-hard williamsburg roof party asymmetrical snackwave waistcoat. Venmo food truck next level raw denim, pabst photo booth quinoa chambray art party hot chicken cliche tote bag polaroid direct trade whatever. Shabby chic lomo locavore slow-carb leggings.</Body>
    <Button>More information</Button>
  </Section>
</root>
ozmo
  • 29
  • 4
  • Can you post your input-XML by editing your question, so we have more background informations?! – uL1 Oct 07 '16 at 05:34
  • You can put the `xsl:choose/xsl:when...`when inside the `td` because the `tr/td` structure is common to both of your choices. – Stefan Hegny Oct 07 '16 at 05:53
  • I'm not clear why you need most of this. All you're really doing is adding the size etc to the image markup, and surrounding it all with the table markup. The anchor part would happen by itself. What's the problem you're trying to solve? – user207421 Oct 07 '16 at 05:54
  • Thanks everyone - The reason the html looks so 1998 is because it's running through a bespoke html email system and I am covering all email clients and especially accounting for the always awesome MSO. – ozmo Oct 07 '16 at 06:49
  • @EJP - As stated above, I'm not really having any issue with my code. It works fine I just wanted to know if there were other, more sophisticated, ways of achieving the same outcome and you guys have provided that so thanks! :) – ozmo Oct 07 '16 at 06:55
  • I wasn't asking about problems with the current implementation, but about what the overall objective is. – user207421 Oct 07 '16 at 09:13
  • @ozmo I have provided an example of DRY, condition-less XSLT code, relevant to your question. I strongly recommend avoiding the use of XSLT conditional operators and adhering to the DRY style demonstrated. – Dimitre Novatchev Oct 09 '16 at 19:31

3 Answers3

1

I would write this as a template:

<xsl:template match="/SupportingImageLink/img">
    <img src="@src" alt="@alt" width="680" .../>
</xsl:template>

and

<tr>
    <td>
         <xsl:apply-templates select="SupportingImageLink/node()"/>
    </td>
</tr>

E&OE

Note that your anchor part will happen by itself via the default copy rule.

user207421
  • 305,947
  • 44
  • 307
  • 483
0

Your question might be answered primarily based on the developers opinion. This is not a good thing on SO. If we are talking about performance or maintainability, there won't/can't be that much opinion-based stuff. If it performs faster, it is faster!

Learned by book "XSLT 2.0 and XPATH 2.0 4.th Edition" published by wrox by lovly Mr. Michael Kay, there are Design Patterns you can follow:

Fill-in-the-blanks stylesheets

Look and feel of HTML and does not use the full power of XSLT. The document is mostly html in addition with some xslt-tag to get dynamic content via e.g. <xsl:value-of .. Kind of your style on that specific project.

Navigational Stylesheet

In addition to Fill-in-the-blanks it goes in direction of "programming". Outsource todos in named templates e.g. <xsl:template name="renderImage". Do more magic than just output a value of an element.

Rule-based Stylesheet

Your main-focus is to transform a xml to an output target. It can vary from pure text to xml validate against any schema to json. You mainly write templates like <xsl:template match="img" and <xsl:template match="a"... You create sets of rules called by <xsl:apply-templates />-statements. You rather say look for rules for this node(-set) and look what rules are defined there than commanding the xslt processor like "do call this named template now and after that call this named template".

Computational Stylesheet

Lets get complex and use the full power of XSLT and write functions, reorder the source-tree to target-tree, create nodes and do this with multiple source and target files. Now you have to understand the concept of functional programming and go beyond the horizon.

uL1
  • 2,117
  • 2
  • 17
  • 28
0

It is perfectly possible to write XSLT code without any conditional instructions.

In fact this is the recommended DRY practice!

  <xsl:template match="Section/SupportingImageLink">
    <tr>
      <td>
        <xsl:apply-templates select="a[@href !='']"/>
        <xsl:apply-templates select="self::*[not(a[@href !=''])]" mode="getImage"/>
      </td> 
    </tr>
  </xsl:template>

  <xsl:template match="SupportingImageLink/a[@href !='']/text()">
    <xsl:apply-templates select="." mode="getImage"/>
  </xsl:template>

  <xsl:template match="node()" mode="getImage">
    <xsl:param name="pImg" select="ancestor::Section[1]/SupportingImage/img"/>
     <img src="{$pImg/@src}" width="680" 
      alt="{$pImg/@alt}" style="border: 0;width: 100%;max-width: 680px;" 
      class="center-on-narrow"></img>
  </xsl:template>

Here is a complete transformation implementing this atop of the most fundamental XSLT Design Pattern: using and overriding the identity rule:

<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="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Section/SupportingImageLink">
    <tr>
      <td>
        <xsl:apply-templates select="a[@href !='']"/>
        <xsl:apply-templates select="self::*[not(a[@href !=''])]" mode="getImage"/>
      </td> 
    </tr>
  </xsl:template>

  <xsl:template match="SupportingImageLink/a[@href !='']/text()">
    <xsl:apply-templates select="." mode="getImage"/>
  </xsl:template>

  <xsl:template match="node()" mode="getImage">
    <xsl:param name="pImg" select="ancestor::Section[1]/SupportingImage/img"/>
     <img src="{$pImg/@src}" width="680" 
      alt="{$pImg/@alt}" style="border: 0;width: 100%;max-width: 680px;" 
      class="center-on-narrow"></img>
  </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the following XML document (the provided one with an additional SupportingImageLink element that hasn't a link with href attribute:

<root>
  <Title>New layout test</Title>
  <Edition>Octovember 2019</Edition>
  <Notification>
  <Body>Warning Warning Warning Will Robinson!! Aliens Aliens Aliens everywhere!</Body>
  </Notification>
  <Introduction>
    <Heading>Squids attack!</Heading>
    <Body>Ugh tacos artisan, single-origin coffee jianbing hoodie skateboard. 
    90's unicorn next level fixie. Glossier coloring book drinking vinegar, 
    health goth flexitarian activated charcoal yuccie hexagon whatever 
    normcore bushwick ethical mustache plaid lyft. Chicharrones edison 
    bulb vinyl disrupt tbh glossier, marfa mumblecore four loko +1 leggings.</Body>
  </Introduction>
  <Section>
    <Heading>Just in - Cyborg bears attacking!</Heading>
    <Structure>3</Structure>
    <SupportingImage>
      <img src="/uploadedImages/dev/robots.png?n=3082" alt="Will Robinson" 
           title="Will Robinson" style="width: 680px; height: 283px;" 
           align="left" width="680" height="283" />
    </SupportingImage>
    <SupportingImageLink>
      <a href="http://www.squids-attack/cyb-bears.html">AAARRRRGGGGHHHH!!!</a>
    </SupportingImageLink>
    <SupportingImageLink>
      <a>AAARRRRGGGGHHHH!!!</a>
    </SupportingImageLink>
    <Body>Ugh tacos artisan, single-origin coffee jianbing hoodie skateboard.
     90's unicorn next level fixie. Glossier coloring book drinking vinegar, 
     health goth flexitarian activated charcoal yuccie hexagon whatever normcore 
     bushwick ethical mustache plaid lyft. Chicharrones edison bulb vinyl 
     disrupt tbh glossier, marfa mumblecore four loko +1 leggings. Knausgaard
      af YOLO, direct trade drinking vinegar try-hard williamsburg roof party 
      asymmetrical snackwave waistcoat. Venmo food truck next level raw denim, 
      pabst photo booth quinoa chambray art party hot chicken cliche tote bag 
      polaroid direct trade whatever. Shabby chic lomo locavore slow-carb leggings.</Body>
    <Button>More information</Button>
  </Section>
</root>

As we see, the wanted, correct output is produced:

<root>
  <Title>New layout test</Title>
  <Edition>Octovember 2019</Edition>
  <Notification>
      <Body>Warning Warning Warning Will Robinson!! Aliens Aliens Aliens everywhere!</Body>
  </Notification>
  <Introduction>
      <Heading>Squids attack!</Heading>
      <Body>Ugh tacos artisan, single-origin coffee jianbing hoodie skateboard. 
    90's unicorn next level fixie. Glossier coloring book drinking vinegar, 
    health goth flexitarian activated charcoal yuccie hexagon whatever 
    normcore bushwick ethical mustache plaid lyft. Chicharrones edison 
    bulb vinyl disrupt tbh glossier, marfa mumblecore four loko +1 leggings.</Body>
  </Introduction>
  <Section>
      <Heading>Just in - Cyborg bears attacking!</Heading>
      <Structure>3</Structure>
      <SupportingImage>
         <img src="/uploadedImages/dev/robots.png?n=3082" alt="Will Robinson"
              title="Will Robinson"
              style="width: 680px; height: 283px;"
              align="left"
              width="680"
              height="283"/>
      </SupportingImage>
      <tr>
         <td>
            <a href="http://www.squids-attack/cyb-bears.html">
               <img src="/uploadedImages/dev/robots.png?n=3082" width="680" alt="Will Robinson"
                    style="border: 0;width: 100%;max-width: 680px;"
                    class="center-on-narrow"/>
            </a>
         </td>
      </tr>
      <tr>
         <td>
            <img src="/uploadedImages/dev/robots.png?n=3082" width="680" alt="Will Robinson"
                 style="border: 0;width: 100%;max-width: 680px;"
                 class="center-on-narrow"/>
         </td>
      </tr>
      <Body>Ugh tacos artisan, single-origin coffee jianbing hoodie skateboard.
     90's unicorn next level fixie. Glossier coloring book drinking vinegar, 
     health goth flexitarian activated charcoal yuccie hexagon whatever normcore 
     bushwick ethical mustache plaid lyft. Chicharrones edison bulb vinyl 
     disrupt tbh glossier, marfa mumblecore four loko +1 leggings. Knausgaard
      af YOLO, direct trade drinking vinegar try-hard williamsburg roof party 
      asymmetrical snackwave waistcoat. Venmo food truck next level raw denim, 
      pabst photo booth quinoa chambray art party hot chicken cliche tote bag 
      polaroid direct trade whatever. Shabby chic lomo locavore slow-carb leggings.</Body>
      <Button>More information</Button>
  </Section>
</root>
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431