← Back to context

Comment by lenkite

3 months ago

You can have template includes that are auto interpreter by the browser - no need to write code AFAIK using XSLT.

XSLT is code. code written with XML syntax. let me give you an example:

in order to create a menu where the current active page is highlighted and not a link, i need to do this:

    <a>
      <xsl:choose>
        <xsl:when test="@name='home'">
          <xsl:attribute name="class">selected</xsl:attribute>
        </xsl:when>
        <xsl:otherwise>
          <xsl:attribute name="href">/</xsl:attribute>
        </xsl:otherwise>
      </xsl:choose>
      home
    </a> |
    <a>
      <xsl:choose>
        <xsl:when test="@name='about'">
          <xsl:attribute name="class">selected</xsl:attribute>
        </xsl:when>
        <xsl:otherwise>
          <xsl:attribute name="href">/about.xhtml</xsl:attribute>
        </xsl:otherwise>
      </xsl:choose>
      about
    </a> |

XSLT is interesting because it has a very different approach to parsing XML, and for some transformations the resulting code can be quite compact. in particular, you don't have an issue with quoting/escaping special characters most of the time while still being able to write XML/HTML syntax. but then JSX from react solves that too. so the longer you look at it the less the advantages of XSLT stand out.

  • You're sort of exaggerating the boilerplate there; a more idiomatic, complete template might be:

      <xsl:variable name="nav-menu-items">
        <item href="foo.xhtml"><strong>Foo</strong> Page</item>
        <item href="bar.xhtml"><em>Bar</em> Page</item>
        <item href="baz.xhtml">Baz <span>Page</span></item>
      </xsl:variable>
    
      <xsl:template match="nav-menu">
        <nav>
          <ul>
            <xsl:apply-templates select="$nav-menu-items/item">
              <xsl:with-param name="current" select="@current-page"/>
            </xsl:apply-templates>
          </ul>
        </nav>
      </xsl:template>
    
      <xsl:template match="item">
        <xsl:param name="current"/>
        <li>
          <xsl:choose>
            <xsl:when test="@href=$current">
              <a class="selected"><xsl:apply-templates/></a>
            </xsl:when>
            <xsl:otherwise>
              <a href="{@href}"><xsl:apply-templates/></a>
            </xsl:otherwise>
          </xsl:choose>
        </li>
     </xsl:template>
    
    

    One nice thing about XSLT is that if you start with a passthrough template:

      <xsl:template match="@*|node()">
        <xsl:copy>
          <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
      </xsl:template>
    

    You have basically your entire "framework" with no need to figure out how to set up a build environment because there is no build environment; it's just baked into the browser. Apparently in XSLT 3.0, the passthrough template is shortened to just `<xsl:mode on-no-match="shallow-copy"/>`. In XSLT 2.0+ you could also check against `base-uri(/)` instead of needing to pass in the current page with `<nav-menu current-page="foo.xhtml"/> and there's no `param` and `with-param` stuff needed. In modern XSLT 3.0, it should be able to be something more straightforward like:

      <xsl:mode on-no-match="shallow-copy"/>
    
      <xsl:variable name="menu-items">
        <item href="foo.xhtml"><strong>Foo</strong> Page</item>
        <item href="bar.xhtml"><em>Bar</em> Page</item>
        <item href="baz.xhtml">Baz <span>Page</span></item>
      </xsl:variable>
    
      <xsl:template match="nav-menu">
        <nav>
          <ul>
            <xsl:apply-templates select="$menu-items/item"/>
          </ul>
        </nav>
      </xsl:template>
    
      <xsl:template match="item">
        <li>
          <xsl:variable name="current-page" select="tokenize(base-uri(/),'/')[last()]"/>
          <a href="{if (@href = $current-page) then '' else @href}"
             class="{if (@href = $current-page) then 'selected' else ''}">
            <xsl:apply-templates/>
          </a>
        </li>
      </xsl:template>
    
    

    The other nice thing is that it's something that's easy to grow into. If you don't want to get fancy with your menu, you can just do:

      <xsl:template match="nav-menu">
        <nav>
          <ul>
            <li><a href="foo.xhtml">Foo</a></li>
            <li><a href="bar.xhtml">Bar</a></li>
            <li><a href="baz.xhtml">Baz</a></li>
          </ul>
        </nav>
       </xsl:template>
    

    And now you have a `<nav-menu/>` component that you can add to any page. So to the extent that you're using it to create simple website templates but you're not a "web dev", it works really well for people that don't want to go through all of the hoops that professional programmers deal with. Asking people to figure out react to make a static website is absurd.

    • wow, thank you. your first example is actually what i have been trying to do but i could not get it to work. i did search for examples or explanations for hours (spread over a week or so). i found the documentation of each of the parts and directives used, but i just could not figure out how to pull it together.

      your last example is what i started out with, including the pass through template. you may remember this message from almost two months ago: https://news.ycombinator.com/item?id=44398626

      one comment for the xslt 3 example: href="" doesn't disable the link. it's just turns into a link to self (which it would be anyways if the value was present). the href attribute needs to be gone completely to disable the link.

      8 replies →