Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Javascript was instantly a hit from the day it was released, and it grew from there.

XSLT never took off. Ever. It has never been a major force on the web, not even for five minutes. Even during the "XML all the things!" phase of the software engineering world, with every tailwind it would ever had, it was never a serious player.

There was, at no point, any reason to invest in it any farther.

Moreover, even if you push a button and rewrite history so that even so it was heavily invested in anyhow, I see no reason to believe it would have ever been a major force in that alternate history either. I would personally contend that it has always been a bad idea, and if anything, it has been unduly propped up by the browsers and overinvested in as it is. But perhaps less inflammatorily and more objectively, it has always been a foreign paradigm that most programmers have no experience in, and this was even more true in the "XML all the things!" era which predates the initial Haskell burst that pushed FP forward by a good solid decade, and the prospects of it ever being popular were never all that great.



i also don't see XSLT solving any problem that javascript could not solve. heck, if you rally need XSLT in the browser, using javascript you could even call some library like saxonjs, or you could run it webassembly.


How do you format a raw XML file in the browser without XSLT?


instead of including a reference to the XSLT sylesheet apparently you can also include javascript: https://stackoverflow.com/a/16426395


That's only if the original document is an XHTML document that will have scripts loaded. Other XML documents, such as RSS feeds, will not have any support for JS, short of something silly like putting it in an iframe.


i didn't test it, but the stackoverflow answers suggested otherwise. are they wrong?


Perhaps you should have tried testing it before commenting?


if you know that the solution does not work, then just say so and maybe explain why, instead of being snarky.

all i did was to share a link to a resource. if you don't trust that resource you need to do your own testing. what ever i say, whether i tested it or not, doesn't add much more value. you can't trust my words any more than the resource i linked.

you asked half a dozen times in the last few days how a plain xml file can be transformed without xslt. and you claimed that xslt can be used to transform an rss feed.

well, guess what, i just tested this: an rss feed with the standard mimetype application/rss+xml doesn't load either an xsl stylesheet or javascript. to make that work you have to change the mimetype, and if you do that, both the xsl stylesheet or the javascript load. (just not both at the same time)


At least one of the suggested answers in SO doesn’t work and the other is somewhat painful

Why answer if you don’t know the answer

Here’s one that used application/xml and it works https://www.ellyloel.com/feed.rss

People are using xslt in the wild today and JS isn’t really a replacement


the specific answer that i linked to does work. i have verified that too.

application/xml is not the same as application/rss+xml. application/xml also loads javascript just fine. again, i tested that. so far i have not found a single mimetype that can load xslt, but could not load javascript. i am coming to believe that there isn't one. if xslt works, then javascript works too.

whether javascript itself is a suitable replacement for xslt is not the question. your argument was that it is not possible to replace the builtin xslt support with anything written in javascript, because xml files can't load javascript.

since i have now verified that an xml file that can load xslt in the browser can also load javascript, this is proven wrong. all we need now is a good xslt implementation written in javascript or maybe a good binding to a wasm one and then we are ready to remove the builtin xslt support in the browser.


I too spent a chunk of time seeing what worked and what it looks like…

JS referenced by the XML can manipulate the XML but it frequently executes before the XML DOM is ready (even when waiting for onload) and so misses elements

So while possible it’s a pretty horrible experience to translate XML to HTML using JS - the declarative approach is more reliable and easier IMV

The XSLT polyfill doesn’t seem to work when loaded as a script in an XML doc but not quite sure why ATM

application/xml is commonly used for RSS feeds on static hosts because it’s the correct mimetype for say a feeds.xml response


https://github.com/mfreed7/xslt_polyfill/pull/5 - it will be able to do this soon.


nice. thanks for the link.

someone else mentioned xjslt here: https://news.ycombinator.com/item?id=44994310 which is an xslt 2.0 implementation. i have been trying to get that to work by loading the script directly into the xml data but so far could not figure out how to do it.


But can it transform / format the XML?


why should it not? once loaded it should find the XML in the DOM and transform that any way you like.


for the record, i just tested that the loaded javascript can access the DOM.


True, but that raises the question, why don't the browsers do that? I think no one would object if they removed XSLT from the browser's core and instead loaded up some WASM/JavaScript implementation when some XSLT is actually encountered. Sort of like a "built-in extension".

Then browser devs could treat it like an extension (plus some small shims in the core) while the public API wouldn't have to change.


because there is no demand for it.


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.


unfortunately i hit another snag: https://stackoverflow.com/questions/3884927/how-to-use-xsl-v...

nodes you output don't have type "node-set" - instead, they're what is called a "result tree fragment". You can store that to a variable, and you can use that variable to insert the fragment into output (or another variable) later on, but you cannot use XPath to query over it.

the xsl documentation https://www.w3.org/TR/xslt-10/#variables says:

Variables introduce an additional data-type into the expression language. This additional data type is called result tree fragment. A variable may be bound to a result tree fragment instead of one of the four basic XPath data-types (string, number, boolean, node-set). A result tree fragment represents a fragment of the result tree. A result tree fragment is treated equivalently to a node-set that contains just a single root node. However, the operations permitted on a result tree fragment are a subset of those permitted on a node-set. An operation is permitted on a result tree fragment only if that operation would be permitted on a string (the operation on the string may involve first converting the string to a number or boolean). In particular, it is not permitted to use the /, //, and [] operators on result tree fragments.

so using apply-templates on a variable doesn't work. this is actually where i got stuck before. i just was not sure because i could not verify that everything else was correct.

i wonder if it is possible to load the menu from a second document: https://www.w3.org/TR/xslt-10/#document

edit: it is!

    <xsl:apply-templates select="document('nav-menu.xml')/menu">
now i just need to finetune this because somehow the $current param fails now.


Ah, I could've sworn that it worked in some version of the page that I tried as I iterated on things, but it could be that the browser just froze on my previously working page and I fooled myself.

Adding xmlns:exsl="http://exslt.org/common" to your xsl:stylesheet and doing select="exsl:node-set($nav-menu-items)/item" seems to work on both Chrome and Librewolf.


tried that, getting an empty match.

here is the actual stylesheet i am using:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:exsl="http://exslt.org/common" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml">
      <xsl:output method="html"/>

      <xsl:variable name="nav-menu">
        <item href="/">Home</item>
        <item href="/about.xhtml">About</item>
      </xsl:variable>

      <xsl:template match="document">
        <html>
          <head>
            <meta charset="utf-8" />
            <title><xsl:value-of select="title" /></title>
            <link rel="stylesheet" type="text/css" href="site.css" />
          </head>

          <body>
            <!-- <xsl:apply-templates select="document('nav-menu.xml')/menu"> -->
            <xsl:apply-templates select="exsl:node-set($nav-menu)/item">
              <xsl:with-param name="current" select="@name"/>
            </xsl:apply-templates>
            <xsl:apply-templates select="content" />
          </body>
        </html>
      </xsl:template>

      <xsl:template match="item">
        <xsl:param name="current"/>
        <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>
      </xsl:template>

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

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

documents look like this:

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <?xml-stylesheet type="text/xsl" href="site.xsl"?>
    <document name="about">
      <title>About Us</title>
      <content>
        html content here, to be inserted without change
      </content>
    </document>
if i use the document() function, with nav-menu.xml looking like this:

    <menu>
      <item href="/">Home</item>
      <item href="/about.xhtml">About</item>
    </menu>
then i get the menu items, but the test <xsl:when test="@href=$current"> fails


It looks like it's related to your setting the default namespace xmlns="http://www.w3.org/1999/xhtml". You could either add a xmlns:example="http://example.org/templates" and then replace `item` with `example:item` everywhere, or you can override the default namespace within your variable's scope:

    <xsl:variable name="nav-menu-items" xmlns="">
        <item href="/">Home</item>
        <item href="/about.xhtml">About</item>
    </xsl:variable>
I think you also don't really need to set the default namespace to xhtml, so I believe you could remove that and not worry about namespaces at all (except for xsl and exsl).

The test is failing because it's `/about.xhtml` in the template but `about` outside. You'd either need to add a name attribute to item to compare on or make it match the href.

That should make your thing work if I haven't fooled myself again. :)


I think you also don't really need to set the default namespace to xhtml

you are right. i removed it, and it works. typical "copy from stackoverflow" error. these namespaces are a mystery and not intuitive at all. i suppose most people don't notice that because it only applies to xml data within the stylesheet. most people won't have that so they won't notice an issue. the less the better.

for the other error, my mistake, duh! in my original example in https://news.ycombinator.com/item?id=44961352 i am comparing $current/@name to a hardcoded value, so if i want to keep that comparison i have to add that value to the nav-menu data. or use a value that's already in there.

i went with adding a name="about" attribute to the nav-menu because it keeps the documents cleaner: <document name="about"> just looks better, and it also allows me to treat it like an ID that doesn't have to match the URL which allows renaming/moving documents around without having to change the content. (they might go from about.xhtml to about/index.xhtml for example)

i am also probably going to use the document() function instead of exsl:node-set() because having the menu data in a separate file in this case is also easier to manage. it's good to know about that option though. being able to iterate over some local data is a really useful feature. i'll keep that around as an example.

the final piece of the puzzle was:

    <xsl:if test="position() != last()"> | </xsl:if>
to put a separator between the items, but not after.

that sorted, now it all works. thank you again.

btw, it's funny that we are turning hackernews into an xsl support forum. i guess i should write all that up into a post some day.


Nice. Fwiw I believe you can also use css for the separators if you've put them in a list:

  li + li::before {
    content: " | ";
  }
If xslt survives maybe I should make a forum and/or wiki. Using xslt of course.


Yeah, unfortunately the one criticism of XSLT that you can't really deny is that there's no information out there about how to use it, so beyond the tiny amount of documentation on MDN, you kind of have to just figure out your own patterns. It feels a little unfair though that it basically comes down to "this doesn't have a mega-corporation marketing it". That and the devtools for it are utterly broken/left in the early 00s for similar reasons. You could imagine something could exist like the Godbolt compiler explorer for template expansion showing the input document on the left and output on the right with color highlighting for how things expanded, but instead we get devtools that barely work at all.

You're right on the href; maybe there's not a slick/more "HTML beginner friendly" way to get rid of the <xsl:choose> stuff even in 3.0. I have no experience with 3.0 though since it doesn't work.

I get a little fired up about the XSLT stuff because I remember being introduced to HTML in an intersession school class when I was like... 6? XSLT wasn't around at that time, but I think I maybe learned about it when I was ~12-13, and it made sense to me then. The design of all of the old stuff was all very normal-human approachable and made it very easy to bite a little bit more off at a time to make your own personal web pages. "Use React and JSON APIs" or "use SSR" seems to just be giving up on the idea that non-programmers should be able to participate in the web too. Should we do away with top level HTML/CSS while we're at it and just use DOM APIs?

There were lots of things in the XML ecosystem I didn't understand at the time (what in the world was the point of XSDs and what was a schema and how do you use them to make web pages? I later came to appreciate those as well after having to work as a programmer with APIs that didn't have schema files), but the template expansion thing to make new tags was easy to latch onto.


devtools for it are utterly broken

right, that's a big issue too. when the xsl breaks (in this case when i use <xsl:apply-templates select="$nav-menu-items/item">) i get an empty page and nothing telling me what could be wrong. if i remove the $ the page works, and the apply-templates directive is just left out.


It solves the problem of not requiring a full turing machine with a giant API that has a history of actual exploits and not just FUD behind it.


i believe XSLT is touring complete, and regarding exploits, you rather want to read this: https://news.ycombinator.com/item?id=44910050

it turns out that because XSLT was largely ignored, it is full of security issues, some of which have been in there for decades.

so the reason XSLT doesn't have a history of exploits is because nobody used it.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: