November 29, 2008
On XLT and javascript

The contest

First of all let me give you the contest of the problem:

On one hand at work we currently are using a content managements system written in Java (whose name I’m not going give) that generates xhtml using far to many XSL transformations. On the other hand we have a .Net application that makes those xhtml pages work with existing .Net applications.

From my point of view the system is not well designed, precisely because the rendering of the pages is done twice, first by the Java content manager system and later by the ASP.Net runtime. Anyway, that i not the problem we had right now.

To simplify the creation of the webpage we have a component/module/widget that allows less technical people to add pure html in the page instead of letting the content system decide how to render the content. This seemed to be a good idea in case there was a more advance user that wanted to use html, but just html.

The problem

The problems started when the business people (the lest technical people) wanted to add Javascripts. Ovioulsy the less tesgnical people were not adding complicated scripts, they were just copy pasting something like:

script language="javascript" src="url"  /script 

In our case the urls was of the form:

javascriptUrli=number&s=data

Now this should have not been a problem, but it was…. This was actually I quite interesting bug to find out. Let met tell you the process that will be used to generate the component in the page:

  1. Get input from user and store it in XML
  2. Perform rendering of the content using a XSLT
  3. Convert the rendering from step 2 to a ASP.Net master page using a XSLT
  4. ISS5 (yes I know…) renders the ASP.Net master page.

After this process for some unknown reason all the & char will be converted to their html representation, and this included or Javascript url converting it from:

javascriptUrli=number&s=data

to

javascriptUrli=number&amps=data

Ouch… the Javascript does not work!!!! Where is this change coming from? After looking at the XSLTs used I discovered one thing, the target of the transformation was XHTML!!!!The processor is outputting XHTML which does not support the & char. Unfortunately the XSLT processor does that with everything, including Javascript.

The solution

There is a way around the problem which is clearly a HACK. All the scripts should be wrapped as if they were html/xml comments.

What does this mean? Well if we used to add the javascript adding:

script language="javascript" src="url"  /script 

We know we should add it using a script like this

var target = document.createElement( "script" );
target.setAttribute(“language”, “javascript”); 
target.setAttribute( "src", "url" );
document.getElementsByTagName( "body" )[0].appendChild( target ); 

The above code should be wrapped by HTML comments tags (I cannot added them because if I do you wont see the code). If Javascript code is wrapped by HTML comments will still work but it will be ignored by the XSLT and therefore the URL won’t be changed :)

Of course this will scare the shit out of a business guy. We can always make it better adding a function that does that with a URL surrounded by HTML comments.

First version

This function will do the trick:

function add_javascript(url){
    var target = document.createElement( "script" ); 
    target.setAttribute(“language”, “javascript”); 
    target.setAttribute( "src", 
        url.replace(/(comment-start-tag)|()comment-end-tag/,””));
    document.getElementsByTagName( "body" )[0].appendChild( target );
}

This will allows the business person to add a Javascript copy pasting:

add_javascript(“(comment-start-tag)url?i=23794804&s=67ECA(comment-end-tag)”)

Obviously surrounding the url with html comment tags.

Second version

Stepah saw my function and decided to improve it by using the replace method of the string object in a much cooler and elegant way:

function add_javascript(url){
    var target = document.createElement( "script" ); 
    target.setAttribute(“language”, “javascript”); 
    target.setAttribute( "src", 
        url.replace(/(comment-start-tag)(.*)(comment-end-tag)/,’$2’));
    document.getElementsByTagName( "body" )[0].appendChild( target );
}

I hope that know you know that is if you are using XSLT you will have problems with Javascript, but you can always use my workaround/hack :)

I hope it helps