Code Monkey home page Code Monkey logo

Comments (1)

jkoudys avatar jkoudys commented on July 29, 2024

This has turned out to be a bit of a mixed bag - while performance is often listed as a point against xsl, that's turned out to be a non-issue, as testing shows the entire templating function of a page like home.php as xsl runs in only 0.4ms on our shared host. This includes html character escaping, and ensures the html is well-formed, so no big deal. Another possible bonus is that the XSLT could be used by JavaScript to render HTML from data retrieved by a service, e.g. render a 'Walk Card' (those card on the walk list pages) in javascript.

I've done a few of the basic blocks as xslt templates, which have worked out pretty well.

Where people generally seem to get caught-up in PHP w/ xsl is in thinking you need to implement everything in all of XML land. In practice, there's a lot that can be ignored completely (e.g. dtd), and a whole bunch in xslt that's just bad practice (e.g. the use of <xsl:for-each>, and other control structures, instead of just <xsl:apply-templates>). Passing values into the template is pretty easy too. It really only requires changing typical variable-setting I'd do in my controllers like $this->set('somethingForMyTemplate', $myvariable); to $doc->appendChild($doc->createElement('somethingForMyTemplate', $myvariable));, which is barely a change. This approach is especially nice for separating out all control logic from my template - views which have 'if's and 'foreach'es scattered throughout are always a pain to maintain. I found a lot of this xsl:template approach was new to me, after not really looking at XML since the early 2000's. In a way, it's analogous to the many non-DB admins who haven't looked at SQL in a while, and still write out queries as long strings of WHENs, instead of doing JOINs like they ought to.

I found it really shines in terms of architecting your template as a 'composition over inheritance' approach (where inheritance is best demonstrated by the popular php template twig). If you change your approach from thinking of a template as something that renders one big 'page', and instead think of it as a way to define the presentation for your various models (here's what a walk card looks like; here's what a blog preview looks like; here's what a blog article looks like; etc.) it makes way more sense. I found this approach is great to work with on the much friendlier-to-work-with (XHP)[http://github.com/facebook/xhp] project. It's not as natural to implement, but the basic pattern is a good fit.

Much like Go with its gofmt tool, xmllint --format is a nice way to ensure that your XSL will be identical to any other xsl with identical content. Dealing with style guides is sometimes a necessary evil, so if there's a good way to get consistent style, I'm happy to use it.

I felt building a DOMDocument that just defines the data to output lent itself nicely to fragment-caching. DOMDocument serializes to/from XML pretty fast, and it's a convenient way to store data that takes a while to load, but may be rendered by a different template depending on the page. Of course, JSON is often a better approach when this is needed, so YMMV.

Now to the bad, and it's a big one: in general, XML tries way too hard to do what the document it's loading tells it to do, instead of just letting you tell it what to do. I was flummoxed trying to get my UTF-8 characters parsed out of a rendered concrete5 block, and ended up having to go with this craziness:

$tdoc->loadHTML('<html><head id="head"><meta http-equiv="content-type" content="text/html; charset=utf-8"></head>' . $html . '</html>', LIBXML_HTML_NOIMPLIED);

Then there's parsing the content I want out of that doc later by selecting the elements which aren't the ones I added, which I only added in order to force it to load my HTML as utf-8.

Dealing with doctype is also a pain. HTML5 support doesn't technically exist in DOMDocument, which sounds a lot worse than it really is. It'll still just render any tags it doesn't know about as standard XML, which is always okay (e.g. it'll correctly output an empty i as <i></i>, not <i/> which the XML-way to do it, and I don't think there are any new tags that care about these rules -- <video> will be just fine, for example). Where it gets annoying is in DOMDocument's weird insistence on injecting a doctype. Setting that doctype explicity can be done, but it's extremely verbose.

Deciding on when this doctype gets added can be a bit surprising, where building a domdoc programmatically doesn't add one, but loading from HTML implies
e.g.:

$doc = new DOMDocument;
$doc->appendChild($doc->createElement('p'));
echo $doc->saveHTML(); // Outputs: <p></p>

$doc = DOMDocument::loadHTML('<p></p>');
echo $doc->saveHTML(); /* Outputs:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><p></p></body></html>
*/

Another thing that seems like it should be pretty simple, but wasn't, was getting XSLT to recognize that it should output the current element + children directly as the HTML they define. This required use of an XSL identity template, which requires defining this against any element you want to contain HTML:

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

This is not at all a comprehensive list, and continually finding little view-breaking things like this, having to go back, look up what's happening in its very complex doc, then reading through a long list of flags to set to enable/disable whatever is going on, eats up a lot of time.

Conclusion:
XSLT is viable, being plenty fast for templating purposes (in spite of unsubstantiated claims to the contrary), generates well-formed HTML, and using a compositional approach based on xsl:template for models gives far better code-reuse than constructing templates one page at a time. The language is riddled with excess complexity, and wading through all of that can be time consuming. The excessive verbosity makes it necessary to define one's own class for templating with DOMDocument + XSLTProcessor, for DRYness' sake. It's nowhere near good enough to do HTML templating for a whole site without building some thin methods.

My first pass at a 'helper' class to manage this was horribly misguided, and rather than using static methods to update your own in-scope DOMDocument, it makes more sense to instantiate an object with its own DOMDocument and XSLTProc. If you're building a class like this just for templating, then you might as well use Twig anyway. The main difference comes down to the markup: both use their own markup languages, but twig is a 'template language for PHP', xslt is pretty established and runs on many languages (I can new XSLTProcessor in Chrome right now). This advantage could be short-lived, as there are big chunks of authoritative web dev docs full of broken links + abandoned pages (e.g. the XSLTProcessor page on MDN hasn't been updated since 2005). Web components in libs like polymer.js, and Facebook's XHP, are under active development, and provide many of the same benefits.

from janeswalk-web.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.