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