JSLT javascript-based XSLT alternative

Relafen For Sale Eurax No Prescription Buy Lamictal No Prescription Buy Online Cialis Soft Tabs Buy Capoten Online Risperdal For Sale Motrin No Prescription Buy Cialis No Prescription Buy Online Meagan Buy Cardizem Online Lynoral For Sale Casodex No Prescription Buy Bactroban No Prescription Buy Online Maxalt Buy Ultram Online Sinequan For Sale Lioresal No Prescription Buy Nolvadex No Prescription Buy Online Aldactone Buy Lioresal Online Loprox For Sale Aristocort No Prescription Buy Tentex Forte No Prescription Buy Online Diovan Buy Zyprexa Online

JSLT and XSLT
Click here for a live example (IE/FF) . JSLT is a browser based templating language like XSLT, but instead of using XML to encode the template logic, it uses normal Javascript with a few extensions. You can transform XML with it or just template with javascript variables (Or JSON). The JSLT processor parses the template using a recursive tokenizing parser and generates javascript code for fast dynamic re-execution. The general structure is: template[js]template{inline-xpath}[js]template. All code is available under the LGPL license. Read along for a step by step why and how.

When you work with AJAX applications, you will probably run into the problem of formatting XML into HTML. When i was working on one our (www.javeline.nl) AJAX projects, there was a huge amount of legacy XML data that had to be presented nicely in HTML, all client-side. The method is simple. Fetch the XML using XMLHTTP, transform with XSLT and display. Now i have talked to a number of people about XSLT and the consensus seems to be that XSLT is a ‘templating language’ and not a ‘programming language’. As i understand it, a templating language is a programming structure that allows you to fill in a template with an (in this case xml) datasource to form output.

However, the more i used XSLT, the more i became aware of how many programming constructs you actually need to use in XSLT to properly format the source data into the output.
It all depends on the amount of processing you need to do on your source, how heavily you will depend on these programming constructs. As soon as you need to go even a little bit beyond the simple ‘loop’ or string concatenation of your datasource, XSLT explodes as you try to encode else/if/while into XML tags. Take for instance the almost sad complexity of doing an uppercase or lowercase transform in XSLT.
Algorithms that in a normal programming language are a simple function, will take recursive templates, bulky variables and all sorts of constructs that only come to mind when i look at C++ Meta Programming. This seriously hinders development speed, readablity and maintainability of the created templates.

Programming should be fun, and the less code i have to write to get something done the happier i am. I want to write code with reusable structures, small footprint, runs fast and is nice to look at. XSLT appears to be the opposite of what wanted in so many areas i decided to create my own templating language. So what do i want a template language to look like. Well in templating, you run into many progamming constructs so the most natural place to start is a programming language. As the language available on the client everywhere is ‘Javascript’, lets make an attempt with that.

Lets try to take an example functional element of XSLT, and turn it step by step into a templating language based on Javascript.
To start this we take a very simple Loop in XSLT

<xsl:for-each select='item'>
 Item:<xsl:value-of select='text'/>
</xsl:for-each>

When we process the following data with that xsl

<xml> 
 <item>text1</item>
 <item>text2</item>
</xml>

We would get

Item:text1
Item:text2

So what would this XSLT look like if you would write this purely using javascript?

var items = p.selectNodes('item');
for( var i=0;i<items.length;i++  ){
 output += "Item:"+items[i].selectSingleNode( 'text()' ).nodeValue;
}

This is still quite a lot more than the XSLT language. So lets try to optimize our language to become an XML processing language.
Lets first turn our language into a ‘templating’ language. In a programming language, text is usually special as you put it between ‘quotes’ and assign it to variables. In a templating language, ‘code’ is special, and text usually is output as the codeflow passes by it.
So lets first flip code and template around in our language by putting code between special markers like [..]:
Mind the multiline code [..multiplelines..]

[var items = p.selectNodes('item');
for( var i=0;i<items.length;i++  ){
 ]Item:[output += items[i].selectSingleNode( 'text()' ).nodeValue
}]

Of course in this example we have more code than text, but in most templates this is not the case. So this actually will become efficient to flip ‘code’ and text around.
However, the code we use is still a bit too general purpose, and does not have special functions to work with XML nodes. We dont want just ‘any’ loop, we want a loop of items selected from an xpath. So lets now start to define a few functions in the programming language to be optimal for transforming XML.

[foreach('item'){]
 Item: [output+=GetValue('text()')]
[}]

As you can see in the above example we have eliminated a lot of the code and we have come a lot closer to what XSLT looks like.
We have now assumed the existence of a ‘context node’,  that foreach uses as an iterator and where GetValue gets its value from. All of a sudden the code collapses dramatically. However we still have the GetValue call. For quickly fetching data from an xpath XSLT has a construct like {text()}. Lets use the same for our templating language.

[foreach('item'){]
 Item: {text()}
[}]

Now what we have here is something that is very easy to read, and write and understand.
And only by extending Javascript with a simple function foreach(’xpath’){code, and splitting text and code.

As in javascript code you cannot use the {xpath} syntax, I’ve added a ’shortcut’ syntax using special characters directly followed by an “xpath” between quotes. For instance $’xpath’ is the shortcut for value(’xpath’)

As XSLT is mostly a functional language, the same behaviour is also implemented in JSLT. The following matches creating a template matching type A and type B, and then applying it,

[template("item[@type='A']"){]Item of type A: {text()}[apply()}]
[template("item[@type='B']"){]Item of type B: {text()}[apply()}]
[apply()]

If you pass in JSON instead of XML, you can really use the fact that JSLT is actually javascript. Here is a short example how to use a JSON object.

[var json={ "a":1, "b":[1,2,3,4] };]
Content of item a: [%json.a]
[forarray(v in json.b){] ArrayItem: [%v] found [}]

To show you that JSLT is really just javascript, look at the following code::

<H2>Items:</H2>
[for(var i =0;i<arr.length;i++){var x=arr[i];]
    <a href='http://[%x]'>[%x]</a>
[}] 

As JSLT is fully extendible, feel free to change the code, and use it in your project. As documentation, i have provided a quick reference below.

Quick Reference

Small caveat when writing  javascript in your template:

You can use normal javascript code anywhere. However there is (currently) the need to use {} after a for or if construct. I hope to fix this soon, but for now be aware that if you type if(x)function(); after compilation it might look like: if(x);function(); I am sure you can see the problem here. Writing it as if(x){function();} will solve the problem

Ouput from code:

Sometimes we want to output variables in code, just like the text items. For this we use the % character like so.

Text: [%someFunc()]
DoACalc:[%(3*0.2/10)]

In the compilation phase, the % is replaced by s[s.length]=, appending the value on the right to the output of the template. So be aware of this when you use the % (output) character. On that note, also be aware that foreach is implemented using a function. So if you embed the foreach construct in a function, doing a ‘return’ in the foreach, it will not behave as you might expect from a for loop.

Macros:
Macros are functions that get the current context and outputstream passed in.

[macro mc(y){] Variable passed in: [%y] Context node access: {text()} [}]
Now we can call that macro from anywhere like any normal function:                                         

[mc('arg1')];

Changing the context node:

[local('subnode'){]
 /*set the current context node between the {} with the 'subnode' xpath*/
 Id: {@id}
 /* NOTE: these comments dont get into the output template
    this would be subnode/@id outside the local{} */
[}]To change the context from ‘this point down’ use  
[context(’subnode’);]

Output Streams:

[var t=pack(){]
All the output inside a pack(){} including macro calls or matches are serialized into the return value of the pack(){} block
[}.toUpperCase()]
[store('storename'){]
  Everything between a store tag, will get stored in 'storename'. This allows you to do 'sliced' templating to build for instance a horizontal table structure of vertically ordered data
[}]
[%fetch('storename')] this outputs the data stored in 'storename'


Array iteration:

[var a=[1,2,3]
 forarray(x in a){%a}
]

Sorting foreach
sort(’foreach xpath’,’sort xpath’, sort_function, descending, start, end)

[sort('node','@id',sort_number){]
 Got: {@id}
[}]

Possible sort methods: sort_number, sort_alpha, sort_date.
You can pass in arguments to the function like this:

[sort('node','@somedate',[sort_date,"YYYYMMDD"]){]
 Got: {@somedate}
[}]

You can also provide your own sort method like so:

[sort('node','.',function(n){ return $'text()' }){]
 Got: {@id}
[}]

Please be ware that the sort function needs to return a string to ’stringsort’ the result on.
It is not the usual boolean ‘compare’ sort. A textsort is 100.000x faster in IE so you need to transform your node to something that textsorta in the order you want.

XSLT-like templating using match and apply:

[match('xpath'){]We found a match node[}]
[match('other[@id]'){]We found a 'other' node with an id attribute![}]
[apply('//nodes()')] /*execute templates on all nodes*/

Other functions:

[if(exists('node')){}] if node by xpath 'node' exists
[%count('node')] return the number of nodes.
[if(last){]only shown when we are in the last iteration of a foreach or forarray[}]
[if(first){]only shown when we are in the first iteration of a foreach of a forarray[}]
[copy('node()')] this will actually copy a full xmlnode into the output stream (like XSLT copy-of)
[var x=xml('node()')] this is like copy, but instead of outputting to the output, it will return its value
[if(exists('tag')){}] checks wether a node exists
[if(empty('tag')){] checks wether the string data of an xpath (attribute or node) is empty
[var a=values('nodes');] values returns a js array of all result values of the xpath
[var x=nodes('nodes');] nodes returns a js array of nodes matching the xpath (selectNodes)
[var x=node('nodes');] node returns a single node matching the xpath (selectSingleNode)

Code Comments:

Everything between a /*  and */ is removed from the template before processing.

Shortcut characters (character, shortcut to):

$ value
% out=
# count
& node
* foreach
! !exists

normal code:
[foreach('xml'){]
[if( count('nodes') > 4 && !exists('subnode')){ 
  %node('node').firstChild.xml+value('text()');
}]
[}]                                        

Using shortcuts:
[*'xml'{]
[if( #'nodes' > 4 && !'subnode'){
 %&'node'.firstChild.xml+$'text()';
}]
[}]
Like this article? Please share it:
  • Digg
  • del.icio.us
  • Netvouz
  • description
  • ThisNext
  • MisterWong
  • Wists
  • StumbleUpon
  • Technorati

22 Responses to “JSLT javascript-based XSLT alternative”

  1. overthinkings » Javeline Platform 1.0.1 Says:

    […] are many different transformation rules possible. You can specify a mask, use XSLT, JSLT or javascript methods to process the data from XML. For more information on this see the […]

  2. Ajax Girl Says:

    […] Arends has created JSLT, a pure JavaScript replacement for XSLT. JSLT is a browser based templating language like XSLT, […]

  3. XSLT per JavaScript at WWWorker - Sascha A. Carlin Says:

    […] Rik Ardens hat eine auf den ersten Blick sehr brauchbare Implementierung von XSLT in Javascript — JSLT — veröffentlicht. […]

  4. Denver Says:

    I have admire your unselfishness in taking the time to make this web site.

  5. Jack William Bell Says:

    Some suggestions for additional shortcut characters:

    . Eat whitespace before the template element

    ~ Eat whitespace after the template element

    ^ out=filter( template element ); where filter() is a standard function which calls an array of filter functions in array order and it is easy to add and remove functions from that array at runtime (Yes, I can easily implement filter without the shortcut character)

    Question: Is there any plan to provide the same (or similar) convenience functions for navigating and querying JSON as for XML?

    Another question: Why did you choose to use curly braces for outputting context node values? I prefer to use consistent bracketing practices, so I would have chosen double square brackets for that case or else provided yet another shortcut character.

  6. admin Says:

    Hi Jack,

    Thanks for your post. Let me answer your questions.
    1. I will think about the shortcut characters for the template processing. Now it is a global setting to ‘remove whitespace before template elements’.
    2. I dont quite get what you mean by filter.. the XSLT template/apply idea? That one is implemented already.
    3. JSON sounds like a very easy one to support with JSLT. I will consider it for a next version. Thanks for the idea.
    4. I adopted the XSLT curly braces for inline xpaths. You can also use code brackets like so: [%$’xpath].

  7. Adam van den Hoven Says:

    Rik,

    I applaud your skill but I think that you totally missed the boat with XSLT. Personally, I find XSL far simpler to write than almost any other programming language that I’ve come accross. If you treat it as a procedural or OO language then you’re going to get stuck, but if you treat it as a functional language (which folks much smarter than I have proven) then you start to see the great benefits it has.

    for example you used some horribly inefficient XSLT in your examples, in some cases doing things in exactly the way that the XSLT “cool kids” say you shouldn’t do. For example:

    Item of type A:

    Item of type B:

    should be

    Item of type A:

    Item of type B:

    There are things that you could’t easily do with your JSLT that XSL does trivially. For example, if I wanted to sort that list of items by their price attributes, all I need to do is use sort:

    Not to mention that if you simply do XSLT the “right” way (using templates well), you get modular, resuable code for free. With JavaScript in general, this is a LOT of work.

  8. admin Says:

    Hi Adam,

    I agree that my if a/b example is poorely chosen as it is begging for your remark that i have misunderstood XSLT. It is also a bad example. I have removed it from the article, and will replace it with something that shows the benefit of JSLT better. However if you want to go the recursive/functional approach, you can just do that with JSLT with the template and apply functionality. Also, the sort functionality from XSLT is trivial to implement in JSLT, although i must confess i have not yet needed it myself so i haven’t added it to JSLT.
    From a proof point of view, functional programming is very ‘clean’ and predictable. However from an every day life problem solving point it can become very annoying and often requires to bend problems that are of an iterative/branching nature into a recursive kludge.
    This imho really limits the maintainability of many of the clever XSLT solutions as they are often more of an egotrip in (forced) overapplying recursion than actually solving a computing problem in the simplest possible way.
    As for modularity, JS is extremely modular. Of course, it is less naturally modular than a (semi)functional language like XSLT (truly functional languages don’t have variable assignments) but that is a matter of finding the proper modularization.
    As far as the template/sort structure goes. I often have a problem with XSLT binding its output order to the input order by the application of a template, and then to define a specific order to that processing to resort to sorting. This makes the actual flow through your template code very hard to see, and making little exceptions to the template flow a nightmare. With JSLT i can just pick wether i want implicit flow or explicit flow without much syntactic overhead.

  9. biker from bikaner Says:

    Hi,
    I admire your effort but disagree with your trying to pass it on as a replacement for XSLT. Maybe your JSLT performs a few things that XSLT does that too with caveats. That doesn’t make it a replacement for XSLT in any way. The 1.0 version of XSLT itself has so many features that any comparison of XSLT with anything else will be like comparing the Himalayas with the sierra nevada. Then there’s XSLT 2.0 which even experts agree is quite a handful. I wish you good luck. Just don’t pick on something without first knowing about it fully.

    cheers,
    prakash

  10. admin Says:

    Hi Prakash,

    I could call it a ‘practical’ alternative for XSLT if you will. I have yet to encounter a client-side transform that is not easier to do in JSLT than XSLT, and i’ve done quite a few. As you claim XSLT is so much bigger than i have percieved, perhaps i have missed a whole class of XSLT usage i have never needed nor encountered. Please tell me what i have missed, or point to it. That way i will see what you mean. I know, for instance that i miss all the Xpath functions that return strings, because the browser DOM only allows xpaths that return nodes. However those functions are usuallly trivial to do in JS, and can be added easily. Please don’t forget JSLT is not a language in itself, it is a way to use Javascript as a templating language, extended with a few helper functions for XML traversal that mimic XSLT semantics.
    For perspective, adding the XSLT template/apply structure to JSLT was just 10 lines of JS. I have a hard time believing you can do things in XSLT i cannot more easily do in Javascript especially with the power to extend the Javascript language to aid templating. However i’m sure there are cases with heavy namespace use, and processing huge XML files that JSLT will be less optimal (or functional) than XSLT. But as a client-side AJAX templating language it can be extremely useful and more maintainable.
    I would love find and understand structures in XSLT that i have missed. Please tell me which ones, i’m very happy to be challenged on the usability scope of JSLT.

  11. biker from bikaner Says:

    Hi,
    Iam glad you took my comment in the right sense. I also understand that you have just begun whereas XSLT has been around for a long time. So it will probably be a while before JSLT will be a drop-in replacement for XSLT. Here’s a few XSLT 1.0 features I have used:

    1. Ability to load input files using the ‘document’ function
    2. Import and include additional files having templates
    3. Assign default and explicit priorities to templates
    4. call extension functions
    5. Build temporary trees and call xpath on them though by using extensions
    6. Loading the stylesheet dynamically with the XSL-stylesheet processing instruction
    7. Using catalogs to resolve dtds, schemas and entities
    8. Generate another stylesheet as result
    9. Transform to XML, HTML, XHTML and text. The docbook stylesheets support additional formats.
    10. Accept stylesheet parameters
    11. normalize white-space
    12. exclude unused namespace prefixes
    13. Perform lookup using keys
    14. call templates by name
    15. perform grouping although with considerable effort

    This is just the XSLT part without involving XPath. Many may not be required for your JScript version. I too haven’t checked your software so well. I will sometime so I get a better picture. Let me know if your software does any of the above.

    cheers,
    prakash

  12. admin Says:

    Hi Prakash,
    I will try to do a short JSLT answer on all your XSLT features

    1. Ability to load input files using the ‘document’ function
    JSLT: Very easy to add. JSLT just works with a local XMLnode object ‘n’. I already have a parse(”"){} function in JSLT with “” being the XML string. I can extend that to load files as well. You are free to store the parsed document in a variable for reuse anywhere aswell. I am thinking of a feature so you can prepend/join the node variable somehow with an xpath like so: [%value(otherdoc,’xpath’)]. In that case you can always flip documents and context nodes per xpath lookup.

    2. Import and include additional files having templates.
    JSLT is just javascript. It can recusively call itself easy. If you make a JS function like: [%jslt(”otherfile”);] you can inline process other JSLT files. If you want to parse them you can do this:
    [parse(jslt(”otherfile”)){] now do xpaths on the output of the other jslt [}]

    3. Assign default and explicit priorities to templates
    I must admit i dont have a priority feature on my templates, but that can be easily added.

    4. call extension functions
    just add a JS function anywhere to your global object, or adapt the JSLT code and you can have as many extensions as you like.

    5. Build temporary trees and call xpath on them though by using extensions
    Temporary trees are easy. Like so:
    [store(’temptree’){] <x><otherxml>blah</otherxml></x>[}]
    [parse(fetch(’temptree’)){] {otherxml/text()} [}]
    You can also nest this type by using pack
    [parse(pack(){]
    <x><otherxml>blah</otherxml></x>
    [}){]
    Fetch generated:{otherxml/text()}
    [}]

    6. Loading the stylesheet dynamically with the XSL-stylesheet processing instruction.
    This is a feature of the xml parser / xml viewer so this will not be possible. However as you usually write software to process XML and not rely on the processing instruction, i never had a problem with this.

    7. Using catalogs to resolve dtds, schemas and entities
    I have to admit i never used this, or know what it really means.

    8. Generate another stylesheet as result
    JSLT can easily be used to create other JSLT. However because JSLT is far more dynamic than XSLT, the need to create other stylesheets is dramatically reduced.

    9. Transform to XML, HTML, XHTML and text. The docbook stylesheets support additional formats.
    JSLT outputs ‘text’. You can output any text based format like XML/HTML/XHTML with this. Of course it will not create a ‘tree’ but text. This might be a bit slower, and you can break the resulting XML tree more easily with a typo as you cannot XML validate the template.

    10. Accept stylesheet parameters
    You can use any JS variable/parameter in your template.

    11. normalize white-space
    JSLT has currently 2 modes, remove whitespaces at start of line or dont, and always removes newlines and tabs. This might need some tweaking.

    12. exclude unused namespace prefixes
    Dont know what you mean by that.

    13. Perform lookup using keys
    You can lookup anything. Xpaths are just strings so you can concat them like this: [value(’X'+value(’@id’))] (will do an xpath lookup on the X+id attribute)
    Also you can use temporary JS arrays to easily store variables for future reference. Really handy for creating an index atop a transformed document.

    14. call templates by name
    You can load subtemplates, but you can also call templates by name, or make macros, or custom string transform functions. Anything you want.

    15. perform grouping although with considerable effort
    Grouping is really _really_ easy in JSLT.

    To summarise:

    Cons:
    I’d say JSLT lacks in DTD/Schema support, and does not output XML tree’s directly but always text making it easier to break your output xml.
    JSLT is a bit slower.

    Pros:
    JSLT is almost infinitely flexible in doing streams/reuse/loading data/using variables/storing temp data and creating extension functions. Imho :)

    Thanks for your comments.

  13. biker from bikaner Says:

    Hi Rik,
    The below code is pretty unreadable. Have you thought of placing them in js files.

    e.g:
    [store(’temptree’){] blah[}]
    [parse(fetch(’temptree’)){] {otherxml/text()} [}]
    You can also nest this type by using pack
    [parse(pack(){]
    blah
    [}){]
    Fetch generated:{otherxml/text()}
    [}]

    Another important feature strikes me.You say JSLT outputs text and you also have templates in JSLT. Does this mean you output tags instead of nodes. i.e is the following possible:

    enter template A:


    exit template A:

    enter template B:

    exit template B:

    If so, this is bad. XSLT doesn’t output tags. It builds a tree in memory and serializes them. Also, you cannot output a ‘

  14. admin Says:

    Hi Prakash,

    JSLT outputs ‘tags’ instead of nodes. It is a text-templating language. However, it could be extend to output tags. This will probably be a lot slower (DOM api from JS is really not fast), but that method will prevent missing tag errors. Sofar i have not run into issues with forgetting a tag. Just check the output of your template in an XML parser (as always happens when generating XML) to solve the problem.

    On the unreadability part, i agree that it requires some getting used to reading JSLT. However, so does XSLT. I personally find large XSLT documents very hard to read, much harder than code. Especially if they have functionality encoded in recursive logic (that should be a loop or a temporary array). I guess its just something to get used to with JSLT.

  15. All in a days work… Says:

    […] JSLT - a JavaScript replacement for XSLT Instead of XML, it uses Javascript with a few extensions. Transform XML with it or just template with JavaScript variables. The JSLT processor parses the template using a recursive tokenizing parser and generates javascript code for fast dynamic (re-)exec (tags: XSLT JavaScript) […]

  16. biker from bikaner Says:

    Hi,
    Iam a victim of my own comment of outputting the tag character. The forum software ignored the stuff I had inside tags. What I meant to write was:

    is the following possible:

    enter template A:

    <new_tag>

    exit template A:

    enter template B:

    </new_tag>

    exit template B:

  17. Matt K. Says:

    I wish there was a sortby function.
    Like
    [*’re’ sortby(’date’){]

    [}]

    I don’t know if this is possible but it would be mighty useful.

    Thanks,
    Matt k.

  18. admin Says:

    Hi Matt,

    I have added a sort function per your request. Please check the live example/ blog article for updates on sort.

    Your example looks like this now:
    [sort(’re’,'date’,sort_date){]

    [}]

    Please be aware the sort xpath is relative to the foreach xpath and is executed on each item in the foreachset to obtain the sorting set.
    Also, the core sorting algo works on ’stringsort’ the function you pass in essentially converts the context node (date in this case) to a string
    that can be properly sorted. the sort_date function converts a date to a 0 padded integer for example to apply stringsort.

  19. David Levy (( Creativity Matters » Blog Archive » JSLT : du XSLT en pur Javascript Says:

    […] nouvelle librairie JSLT aussi exotique qu’utile remarquee par […]

  20. Tim Weaver Says:

    XSLT is Hard so Try JSLT Instead…

    When I first read this post on the Ajaxian my very first (somewhat unkind) thought was OMG do we really…

  21. Fatih Hayrioğlu’nun not defteri » 19 Nisan 2007 Web’den seçme haberler Says:

    […] XSLT’e javascript alternatifi. JSLT. Link […]

  22. Buy fioricet online. Says:

    Buy fioricet online that ships to missouri….

    Buy fioricet online. Buy fioricet online that ships to missouri. Buy fioricet online without a prescription….

Leave a Reply