Readit News logoReadit News
Posted by u/Evidlo a day ago
Show HN: JavaScript-free (X)HTML Includesgithub.com/Evidlo/xsl-web...
(spoiler: its XSLT)

I've been working on a little demo for how to avoid copy-pasting header/footer boilerplate on a simple static webpage. My goal is to approximate the experience of Jekyll/Hugo but eliminate the need for a build step before publishing. This demo shows how to get basic templating features with XSL so you could write a blog post which looks like

  <?xml version="1.0"?>
  <?xml-stylesheet type="text/xsl" href="/template.xsl"?>
  <page>
      <title>My Article</title>
      <content>
          some content
          <ul>
              <li>hello</li>
              <li>hello</li>
          </ul>
      </content>
  </page>
Some properties which set this approach apart from other methods:

  - no build step (no need to setup Jekyll on the client or configure Github/Gitlab actions)
  - works on any webserver (e.g. as opposed to server-side includes, actions)
  - normal looking URLs (e.g. `example.com/foobar` as opposed to `example.com/#page=foobar`)
There's been some talk about removing XSLT support from the HTML spec [0], so I figured I would show this proof of concept while it still works.

[0]: https://news.ycombinator.com/item?id=44952185

See also: grug-brain XSLT https://news.ycombinator.com/item?id=44393817

tannhaeuser · 18 hours ago
This is how the simplest variant of SGML (or XML) entities have worked since 1986:

    <!doctype html [
      <!entity e system "e.html">
    ]>
    <html>
      <title>Hello, world!</title>
      <p>The content of e is: &e;</p>
    </html>
HTML was envisioned as an SGML vocabulary from day one. That SGML's document composition and other facilities were used only at authoring time and not directly supported by browsers was merely due to the very early stage of the first browser software ([1]) which directly mentions SGML even, just as HTML specs have presented HTML as a language for authoring and not just delivery since at least version 4.

There really never had been a need or call for browser devs to come up with idiosyncratic and overcomplicated solutions relying on JavaScript for such a simple and uncontroversial facility as a text macro which was part of every document/markup language in existance since the 1960s.

[1]: https://info.cern.ch/hypertext/WWW/MarkUp/MarkUp.html

the_mitsuhiko · 14 hours ago
> This is how the simplest variant of SGML (or XML) entities have worked since 1986:

In theory. In practice not a single browser had an actual SGML parser and that was never supported.

bawolff · 9 hours ago
Entities are also probably a significant reason for XML's bad reputation. Between using them to leak senditive files (XXE), and recursive expansion being a DoS vector (million laughs), it cemented XML's reputation as a security risk.

In the browser context though, i don't see why they couldn't just follow same origin rules.

tannhaeuser · 8 hours ago
I was surprised this wasn't brought up earlier, as it always is in these discussions. It's trivial to mitigate security risk arising out the use of entities. SGML even has the CAPACITY ENTLVL built-in entity nesting limit.

TBH, a browser has one million other potential leaks and exploits and denials to care about. Unlike a markup language with carefully crafted rules about what to expand in which context, a browser providing a Turing-complete language trivially runs into infinite loops or recursion and could at best heuristically terminate JS code, after using laborious best-efforts methods such as execution traces and watchdog timers. Moreover, JS syntax itself and how it's represented in markup unneccessarily gives rise to obfuscation and escaping attacks. And the browser in addition also plays fast and loose with an ever-expanding, potentially Turing-complete styling language with super complicated styling syntax and constraint-based layout models with a complete lack of formal semantics or any other formal reasoning. CSS itself can contain HTML literals at several places such as data URIs and the content property with questionable escaping, but I guess this is par for the course when CSS is basically just tunneling yet another syntax through HTML attributes and elements. Context Security Policy is just bolted on to limit this pointless and careless gratuitious syntax proliferation, and of course must invent its own little item-value microsyntax to be tunneled through HTTP headers and HTML header tags.

Considering these glaring and obvious deficits weren't discussed at the same time I assume those who brought up XXE and suggested SGML/XML could leak documents or smuggle executable instructions did so in bad faith or were repeating hearsay to sound clever or something.

myfonj · 16 hours ago
I wish external entities were enabled in browsers (*), and not entirely disabled, like they are now.

In the OP scenario, it would provide possibility to have header/footer/stylesheet content in separate files and get system working that does not rely on absolute path of the CSS.

(*) Naturally, just with few minimal directory traversal precautions; basically anything like "no ../" and even restriction like "referenced resource filename must begin with referencing XSL filename" would be fine for me.

DonHopkins · 15 hours ago
XULRunner (Firefox, Thunderbird, Songbird, Miro, Joost, TomTom Home, etc) abused XML external entities in language specific DTDs for internationalization / localization.

https://www-archive.mozilla.org/projects/intl/iuc15/paper/iu...

https://en.wikipedia.org/wiki/XULRunner

bawolff · a day ago
Since this seems to be about the recent proposal to remove xslt, i'd point out you can do the same thing with CSS

https://bawolff.net/css-website/index.xml is Evidlo's example but using a css stylesheet instead of xslt. I changed some of the text to explain what i was doing, but otherwise the XML is unchanged with one exception. Unfortunately you do have to put the <a> tags in the xhtml namespace to make them clickable. Other than that no changes to the xml.

Obviously there is a lot that xslt can do that css cannot, but when it comes to just display, CSS is an option here.

egeozcan · 20 hours ago
This is really, definitely cool, but it's important to remember that content added via CSS is purely decorative. It can't be interacted with, which is a major issue for assistive technologies like screen readers.
lelandfe · 11 hours ago
I learned recently that you can provide accessible labels for content: https://www.stefanjudis.com/today-i-learned/css-content-acce...

I haven’t yet cracked open a screen reader to see how it fares, though.

8organicbits · a day ago
> there is a lot that xslt can do that css cannot

This latter part is why I've reached for XSLT in the past. Most recently was to convert an RSS feed into a styled page with instructions at the top. Templates and xpath can really transform a document.

Evidlo · 20 hours ago
Thanks for the CSS example.

By the way, the advanced/ folder has a slightly more complicated example that demonstrates template inheritance and "slots".

bawolff · 18 hours ago
Yeah, i saw. Unfortunately the advanced example wouldn't be doable in CSS. I suppose i'm being a bit intellectually dishonest to not explicitly point that out.
em-bee · 16 hours ago
that feels a bit to simplified. i'd like to see an example that includes at least some html, and maybe clickable links. it's maybe also worth showing that you can include images with css.
lenkite · 19 hours ago
Umm..your CSS example doesn't show any template includes. No way to put header/footer in separate files.
em-bee · 16 hours ago
but they are in a separate file. the css file. you an load multiple css files if you want to break it out.
bawolff · 18 hours ago
The original example didn't have that either.
Pxtl · 20 hours ago
> i'd point out you can do the same thing with CSS

Cool when are they removing CSS from the standard?

Kuyawa · 10 hours ago
20 years ago I saw the greatness of xml and xslt as I was coming from the painful inferno of an EDI shop. There is nothing more beautiful than sending plain data to a client and being able to see the whole document without any extra bloating, that's what XSLT was intended for:

  <?xml version="1.0"?>
  <?xml-stylesheet type="text/xsl" href="/invoice.xsl"?>
  <invoice>
    <date>2025-08-23</date>
    <customer>
      <name>John Doe</name>
      <address>
        <line>123 Sunny Boulevard</line>
        <city>Miami</city>
        <state>FL</state>
        <zip>33133</zip>
      </address>
    </customer>
    <items>
      <item>
        <code>123456</code>
        <description>Some Apple gadget</description>
        <quantity>1</quantity>
        <price>1234.56</price>
        <total>1234.56</total>
      </item>
      <item>more items...</item>
    </items>
  </invoice>
That piece of data would be sent to millions of customers and they could open it and the XML was transformed in an invoice perfectly formatted for human consumption. Both flesh and silicon were living happy in perfect harmony.

Then it came SOAP and all the corporate suits and messed it all up into an extra complicated bloatness of anguish and suffering, but XML/XSLT were beautiful on their own (for data transformation, not web pages)

Kuyawa · 9 hours ago
If we extrapolate it all to JSON, all we need to do is add two lines to the data file to reference the JSLT source and then use any templating system as default (ejs, mustache, handlebars) to do the transformation in the browser

  {
    "JSLT": "1.0",
    "style": "/invoice.jsl",
    "data": {
      "invoice":{
        "date": "2025-08-23",
        "customer": {
          "name": "John Doe",
          "address": {
            "line": "123 Sunny Boulevard",
            "city": "Miami",
            "state": "FL",
            "zip": "33133",
          },
        },
        "items": [
          {
            "code": "123456",
            "description": "Some Apple gadget",
            "quantity": "1",
            "price": "1234.56",
            "total": "1234.56",
          },
          {
            "code": "123457",
            "description": "Another Apple gadget",
            "quantity": "1",
            "price": "1234.57",
            "total": "1234.57",
          }
        ]
      }
    }
  }
Then the JSLT file:

  <html>
  <body>
    <h2>Invoice</h2>
    <p><label>Date</label> <span><%=data.invoice.date%></span></p>
    <div>
      <h3>Customer</h3>
      <p><%=data.invoice.customer.name%></p>
      <p>
        <%=data.invoice.customer.address.line%>
        <%=data.invoice.customer.address.city%>
        <%=data.invoice.customer.address.state%>
        <%=data.invoice.customer.address.zip%>
      </p>
    </div>
    <table>
      <tr>
        <th>Code</th>
        <th>Description</th>
        <th>Quantity</th>
        <th>Price</th>
        <th>Total</th>
      </tr>
      <% for(item of invoice.items) { %>
        <tr>
          <td><%=item.code%></td>
          <td><%=item.description%></td>
          <td><%=item.quantity%></td>
          <td><%=item.price%></td>
          <td><%=item.total%></td>
        </tr>
      <% } %>
    </table>
  </body>
  </html>
Then we could get rid of XSLT

xnx · a day ago
Why didn't HTML imports stick around? https://web.dev/articles/imports
lloydatkinson · a day ago
The moronic Web Component cabal got their hands on it and trashed it by forcing it to rely on JavaScript, thus ensuring it would never get support.
spankalee · 20 hours ago
I'm sorry, this a dumb comment that has no basis in reality.

HTML Imports was part of the initial set of the web components specs, there's no "cabal" or whatever that got its hands on it, and it didn't rely on JavaScript, not in the way you're probably referring to.

It was only opposed because it was separate from the JS module system, not because it relied on JS.

It's replacement: The HTML Modules proposal has general support from all vendors, just no one has put together a complete proposal yet.

abraham · a day ago
For a long time web components generally built on four standards:

  - Custom HTML elements
  - Shadow DOM
  - HTML imports
  - HTML templates
https://korban.net/posts/elm/2018-09-17-introduction-custom-...

Eventually it became clear some browsers were not going to implement and the design of HTML imports was better handled be ES modules.

https://webmasters.stackexchange.com/questions/127482/on-wha...

bapak · a day ago
Found this, it should answer your complaints:

> HTML Imports were redundant, since you need JavaScript to bring them alive anyways

shakna · a day ago
As of the next version of Chrome, XSLT will be gated behind a flag.

Google have also asked for it to be removed from the standard [0].

[0] https://github.com/WHATWG/html/issues/11523

chrismorgan · a day ago
> As of the next version of Chrome, XSLT will be gated behind a flag.

Citation? That would greatly surprise me in its abruptness and severity (they only just started talking about it this month, and acknowledge it’s particularly risky for enterprise) and https://chromestatus.com/feature/4709671889534976 gives no such indication.

shakna · a day ago
The meeting referenced there, from March not last month, also gives no indication that they'd go ahead and make any moves - "stick a pin in it". But they did anyway. [0]

panos: next item, removing XSLT. There are usage numbers.

stephen: I have concerns. I kept this up to date historically for Chromium, and I don't trust the use counters based on my experience. Total usage might be higher.

dan: even if the data were accurate, not enough zeros for the usage to be low enough.

mason: is XSLT supported officially?

simon: supported

mason: maybe we could just mark it deprecated in the spec, to make the statement that we're not actively working on it.

brian: we could do that on MDN too. This would be the first time we have something baseline widely available that we've marked as removed.

dan: maybe we could offer helpful pointers to alternatives that are better, and why they're better.

panos: maybe a question for olli. But I like brian's suggestion to mark it in all the places.

dan: it won't go far unless developers know what to use instead.

brian: talk about it in those terms also. Would anyone want to come on the podcast and talk about it? I'm guessing people will have objections.

emilio: we have a history of security bugs, etc.

stephen: yeah that was a big deal

mason: yeah we get bugs about it and have to basically ignore them, which sucks

brian: people do use it and some like it

panos: put a pin in it, and talk with olli next time?

panos: next thing is file upload control rendering

[0] https://github.com/whatwg/html/issues/11146#issuecomment-275...

simpaticoder · a day ago
It's kind of too bad XSLT didn't take off. It is quite complex, until you compare it to the complexity of what now solves this problem (e.g. a build step with React and webpack and javascript absolutely required on the client-side). As the OP ably demonstrates, XSLT provides a declarative, non-javascript, non-build way to solve the basic HTML component problem. Perhaps a devastating 0-day in V8 will make us really, really want an alternative to the current best practice.
shakna · a day ago
Whilst I can't be certain, I've been hearing that part of Google's want to move away from XSLT is two-fold - and relates to the idea of the security problem.

Partly, there's increasing attacks against XML.

And also, libxml2 has said "no" to security embargoes altogether. [0]

They might well consider there to be 0-days waiting in XSLT.

[0] https://news.ycombinator.com/item?id=44381093

MrJohz · 21 hours ago
I think the big difference there is that browsers are only responsible for Javascript, which is a big general purpose solution that solves a lot of problems and not just templating/styling XML. Everything else either happens server-side (build steps and webpack) or is userland code that lives inside the sandbox. So there's one task for browsers to do (make a fast and secure Javascript sandbox), and if that works that developers can do whatever they want. Whereas XSLT is not a general purpose tool in the same way, and so needs to be maintained in addition to Javascript and anything else that exists.

If course XSLT can also be used server-side (which is probably a good idea if you want access to the latest features and not some ancient, frozen version of the spec), but browsers aren't the reason that that didn't take off. My guess there is that it's just not an intuitive way of manipulating and templating data in comparison to more traditional HTML templating libraries.

AgentME · a day ago
React supports rendering to HTML ahead of time (SSR) which doesn't need any client-side javascript, and this is a prominent feature of most frameworks using React. This feature of React was one of its major innovations over many other front-end frameworks of the time.
bawolff · 21 hours ago
I don't think react is comparable.

React's main thinh is client side reactivity, something that xslt doesn't offer.

A closer comparison would be a templating engine that does statuc conversion to html.

notpushkin · a day ago
Yeah, I think that was what prompted this submission.

All this has also reignited my idea for a compile-to-XSLT templating language, too – maybe I’ll get to it finally this time; definitely if XSLT 3.0 gets into web standards: https://github.com/whatwg/html/issues/11578, https://news.ycombinator.com/item?id=44987552

Also, I’ve put together a simple XSLT playgroung a while ago! https://xsltbin.ale.sh/

bokchoi · 8 hours ago
I haven't tried it yet, but I came across this alternate syntax for XSLT which is much more friendly:

https://github.com/Juniper/libslax/wiki/Intro

Evidlo · 20 hours ago
I was thinking it would be possible to compile a subset of Jinja2 (or your favorite equivalent) into XSL: https://chatgpt.com/share/68a95439-ad54-800a-919f-23caecce43...

Thanks for the playground! I'll check it out.

SnuffBox · a day ago
I find it bizarre that Google can just ask for a feature to be removed from standard and nobody bats an eye.
johncolanduoni · a day ago
To be fair, some things should be legitimately considered to be removed from the standard. O.G. XHTML basically mandated that you accept XML logic bombs and we got over that.

Also, while this is certainly Google throwing their weight around, I don’t think they are doing it for monetary advantage. I’m not sure how removing XSLT burnishes their ad empire the way things like nerfing ManifestV3 have. I think their stated reasons - that libxslt is a security disaster zone for an obscure 90s-era feature - is earnest even if its not actually in the broader web’s best interests. Now that Safari is publicly on board to go second, I suspect it’s an inevitability.

notpushkin · a day ago
If I understand correctly, Mozilla and Apple don’t really want to support it either. And the reason for that is, the spec is still at XSLT 1.0, which is super old, and current implementations are effectively abandonware. Catch-22?
esrauch · a day ago
It doesn't seem weird at all to me: standard is essentially the consensus of the major browser vendors; a spec which all of Chrome, Safari and Edge don't implement is really just a hypothetical.

The origin story of whatwg is that Apple, Mozilla and Opera decided that W3C wasn't making specs that they wanted to implement, so they created a new working group to make them.

chrismorgan · a day ago
> nobody bats an eye

I’ve seen a lot of eye-batting about this. Although Google, Mozilla and Apple are all in favour of removing it, there’s been a lot of backlash from developers.

TiredOfLife · 15 hours ago
Mozilla asked for removal. Google just filled the paperwork
ekianjo · a day ago
Even "champion of the web" Mozilla is on board. Tells you exactly what you need to know.
kome · a day ago
so it's time to use XSLT more
ulrischa · 19 hours ago
To overcome the two problems here (client side loading the template and ending browser support) you could throw in php in the mix and have a wonderful solution for templating with bullet proof standards: // XML $xml_doc = new DOMDocument(); $xml_doc->load("file1.xml");

// XSL $xsl_doc = new DOMDocument(); $xsl_doc->load("file.xsl");

// Proc $proc = new XSLTProcessor(); $proc->importStylesheet($xsl_doc); $newdom = $proc->transformToDoc($xml_doc);

// Output print $newdom->saveXML();

XSLT lacks functionality? No problem, use php functions in xslt: https://www.php.net/manual/en/class.xsltprocessor.php

Telemakhos · 10 hours ago
What you're describing is basically Symphony, the CMS built around XSLT with some PHP and MySQL to glue things together: https://github.com/symphonycms/symphonycms

I don't think it's been updated since 2019. XSL was really powerful, but it had a steep learning curve, and I think server-side PHP and client-side JS were just more intuitive.

ulrischa · 7 hours ago
Cool project. Sadly it seems to be unmaintained
mgr86 · 21 hours ago
A small comment for anyone new to xslt. The author references a wildcard rule in the comments [0]. While that is true, they are calling an identity transformation [1]. Identity transformations are very common in xslt.

[0] https://github.com/Evidlo/xsl-website/blob/0dda1d82ce1eb01b7... [1] https://en.wikipedia.org/wiki/Identity_transform

raggi · a day ago
I used to do this in the 2000's era, there was a lot to love about it. At the time though the IE engines were far more complete and less buggy than others with various XML features.