How to test Sarissa in your browser with ECMAUnit

Sarissa tests are written using ECMAUnit, a unit testing framework for ECMAScript (a.k.a. JavaScript). You can test Sarissa against your browser here. Please note that some tests may fail if you run those directly from your filesystem due to security restrictions in your browser; use a web server instead.

[top]

How can I compress the javascript files?

You don't have to. You can find compressed versions of each file along with the original ones. To use them, simply append "-compressed.js" (without the quotes) to the original file names when importing them to your webpage. We use the MobilVox Maven JavaScript Plugin to make the compressed versions, which are also used in our ECMAUnit tests.

[top]

How to obtain a DOM Document object

Obtaining a DOM Document object is as easy as calling a factory method:

    // Get a browser-specific DOM Document object
    var oDomDoc = Sarissa.getDomDocument();
       

Additionally, you can also pass two string parameters to that factory method. These parameters are a namespace and a local name respectively. Their combination builds the Document Element thus:

    var oDomDoc = Sarissa.getDomDocument("http://foo.org/ns/uri","foo");
       

will build a representation of the following into memory:

    <foo xmlns="http://foo.org/ns/uri"></foo>
       

In Mozilla, calling the Sarissa.getDomDocument method as above is equivalent to:

          var oDomDoc = document.implementation.createDocument("http://foo.org/ns/uri","foo", null);
       

In the case you are using Internet Explorer, the Sarissa.getDomDocument method returns a DOM Document object, using the most recent MSXML ProgID available in your system for that Class. So supposing MSXML4.0 is available, the equivalent statement for IE is:

    var oDomDoc = new ActiveXObject("Msxml2.DOMDocument.4.0");
       

If the arguments to the factory method include a namespace URI and node name, the proper DocumentElement is built and inserted in the Document object in IE as well.

[top]

How to obtain an XMLHTTP Request object

Creating an XMLHTTP/XMLHttpRequest is as easy as

    var xmlhttp = new XMLHttpRequest();
       

In IE 7 this works ASIS. For users under IE prior to version 7, an XMLHTTP object is returned using the most recent MSXML ProgID found in the client system. So, supposing that the user has MSXML4.0 installed, the above is equal to:

    var xmlhttp = new ActiveXObject("Msxml2.XMLHTTP.4.0");
       

But with Sarissa you do not need that, the code can be the same for all browsers so:

    var xmlhttp = new XMLHttpRequest();
    xmlhttp.open("GET", "http://foo.org/someDocument.xml", false);
    // if needed set header information 
    // using the setRequestHeader method
    xmlhttp.send('');
    alert(new XMLSerializer().serializeToString(xmlhttp.responseXML));
       

... will load the document from the server and then throw an alertbox with the contents of the file to your screen. XMLHTTP objects support both synchronous and asynchronous loading of remote XML documents (note the third parameter of the xmlhttp.open method above). In asynchronous loading, you will probably want to call a function to handle the object readystatechange events, see if loading is completed and then do whatever. To do that, add your onreadystatechange handler function before calling the send method. Something like:

    xmlhttp.onreadystatechange = function() {
      if(xmlhttp.readyState == 4)
      alert("Finished loading!");
    };
       
[top]

How to load an XML Document Object from an XML String

You can also make a DOM Document "load" using an String variable with XML content. It's pretty simple using the DOMParser object:

    var oDomDoc = Sarissa.getDomDocument();
    var xmlString = "<root>my xml!</root>";
    oDomDoc = (new DOMParser()).parseFromString(xmlString, "text/xml");
    alert(new XMLSerializer().serializeToString(oDomDoc));
       
[top]

How to serialize an XML DOM node to a string

To serialize an XML DOM Node simply feed it to an XMLSerializer object:

    var xmlString = new XMLSerializer().serializeToString(someXmlDomNode);
       
[top]

How to check for parsing errors

You can check for and get a human-readable description of the error using the Sariss. getParseErrorText method, passing the document as the argument:

    if(Sarissa.getParseErrorText(oDomDoc) == Sarissa.PARSED_OK){
      // The document was parsed/loaded just fine, go on
      doSomething(oDomDoc);
    } 
    else{
      // The document was not loaded correctly! Inform the user:
      alert(Sarissa.getParseErrorText(oDomDoc));
    };
       

Sarissa.getParseErrorText will return one of:

  • Sarissa.PARSED_OK if the document was parsed with no errors
  • Sarissa.PARSED_EMPTY if the document is empty (this may occur instead of an error using XmlHttpRequest)
  • Sarissa.PARSED_UNKNOWN_ERROR if the document was not loaded for an unknown reason
  • A human readable description of the parsing error

Tip: Wrap the result of Sarissa.getParseErrorText in a "pre" element if you want to render it.

If you have used the deprecated .load methods, you can also use the parseError property. The property always gives an integer, anything other than zero signals an error.

    // ...
    oDomDoc.async = false;
    oDomDoc.load("someDocument.xml");
    if(oDomDoc.parseError.errorCode != 0)
      alert("not well formed or other error!");
    else
      alert("loaded ok");
       
[top]

How to transform a DOM Document Object with XSLT

In general, Sarissa uses the browser's native XSLTProcessor to control XSLT transformations. This includes Mozilla/FF, Opera, Webkit and IE. Sarissa transparently provides an implementation of XSLTProcessor for the latter. Notes::

  • Some browsers have element name insensitivity issues. This does not matter a lot in HTML, but may require caution in some cases. Check out Sarissa's unit tests with different browsers to see what I mean.
  • Using HTML as the transformation output usually results in trouble for IE.
  • Older versions of Safari/Webkit have no support for XSLT via JS. A solution is to use Sarissa with Javeline.

The XSLTProcessor object allows reusability of stylsheets; with it you can use the same stylesheet on more than one source file. You use the XSLTProcessor to control transformations and set / get stylesheet parameters as in the following example:

    // create an instance of XSLTProcessor
    var processor = new XSLTProcessor();
    
    // create a DOM Document containing an XSLT stylesheet
    var xslDoc = Sarissa.getDomDocument();
    var xslStr = "&lt;?xml version='1.0' encoding='UTF-8'?&gt;"+
    "&lt;xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform' &gt;"+
    "&lt;xsl:output method='html' version='1.0' encoding='UTF-8' indent='yes'/&gt;"+
    "&lt;xsl:param name='title'&gt;&lt;xsl:value-of select=\"'default title'\"/&gt;&lt;/xsl:param&gt;"+
    "&lt;xsl:template match='/'&gt;&lt;p class='test' title='{$title}'&gt;test&lt;/p&gt;"+
    "&lt;/xsl:template&gt;&lt;xsl:template match='@*'&gt;"+
    "&lt;/xsl:template&gt;&lt;/xsl:stylesheet&gt;";
    xslDoc = (new DOMParser()).parseFromString(xslStr, "text/xml");
    
    // make the stylesheet reusable by importing it in the 
    // XSLTProcessor
    processor.importStylesheet(xslDoc);
    
    
    // now XSLTProcessor is the 'proxy' for our stylesheet,
    // the function below demonstrates usage
    function test(paramValue) {
      // set a stylesheet parameter
      processor.setParameter(null, "title", paramValue);
      // create source document
      var xmlDoc = Sarissa.getDomDocument("http://foo.org/ns/uri","foo", null);
      // transform the document 
      var newDocument = processor.transformToDocument(xmlDoc);
      // show transformation results
      alert(new XMLSerializer().serializeToString(newDocument));
    }
    
    
    // test the above function
    test("test 1");
       
[top]

How to use XSLT/XPath in browsers that provide no XPath/XSLT support?

The Javeline folk have created an XPath/XSLT compatibility library in pure javascript. The library is available for download on their dev site. To use the library with Sarissa, import the scripts to your webpage in the folowing order:

  1. sarissa.js
  2. javeline_xpath.js
  3. javeline_xslt.js
  4. Other Sarissa files you might need like sarissa_dhtml.js

The Javeline XPath/XSLT compatibility library will provide implementations of XSLTProcessor and IE's XPath related extentions (i.e. selectNodes etc.).

[top]

How to submit an HTML form using AJAX?

Use the Sarissa.updateContentFromForm method:

    <div id="targetId"> this content will be updated</div>
    <form action="/my/form/handler" method="post" 
      onbeforesubmit="return Sarissa.updateContentFromForm(this, document.getElementById('targetId'));">
       

If JavaScript is supported, the form will not be submitted. Instead, Sarissa will scan the form and make an appropriate AJAX request, also adding a parameter to signal to the server that this is an AJAX call. The parameter is constructed as "Sarissa.REMOTE_CALL_FLAG=true" so you can change the parameter name simply by assigning another value to Sarissa.REMOTE_CALL_FLAG. If JavaScript is not supported the form will be submitted normally. Optionally, the response may be transformed before injected to the page, see also the API docs.

[top]

How to update areas in your webpage from remote (optionally transformed) XML documents or XML DOM Nodes using only one line of code!

Loading a DOM document from a URL, transforming it and using it to update the content of an HTML element is a very common task if you are into "AJAX" apps. With Sarissa you can do it in a single line of code:

    Sarissa.updateContentFromURI(sFromUrl, 
        oTargetElement, xsltproc, callback, skipCache);
       

The parameters used here are:

  1. sFromUrl: the URL to make the request to, e.g. "http://localhost/mydoc.xml"
  2. oTargetElement: the element to update, e.g. document.getElementById('content')
  3. xsltproc (optional): the transformer to use on the XML Document before updating the target element with it
  4. callback (optional): a Function object to execute once the update is finished successfuly, called as callback(oNode, oTargetElement)
  5. skipCache (optional): whether to skip any cache

Quite similarly, if you want to use an XML DOM object instead of a remote XML document simply take a look at Sarissa.updateContentFromNode

Note: To use updateContentFromURI or updateContentFromNode you need to include sarissa_dhtml.js in your HTML page.

[top]

How to use XPath from JavaScript to select Nodes from an XML Document

Mozilla fully implements DOM Level 3 XPath so it was pretty trivial to implement IE's basic selectNodes and selectSingleNode methods, with full namespaces support. This is available in sarissa_ieemu_xpath.js. Actually IE also needs the proprietary setProperty method for it's XPath implementation to work. setProperty is used for a number of things in IE. First you'll have to use it to make XPath available for a certain document:

    oDomDoc.setProperty("SelectionLanguage", "XPath");
       

In IE, using selectNodes or selectSingleNode without the above first will give an error. Also, the same method with different parameters is used to allow IE to resolve namespace prefixes, for example:

    oDomDoc.setProperty("SelectionNamespaces", 
    "xmlns:xhtml='http://www.w3.org/1999/xhtml'");
       

If you want to allow IE to resolve multiple namespace prefixes, use a space delimited list like:

    oDomDoc.setProperty("SelectionNamespaces", 
    "xmlns:xhtml='http://www.w3.org/1999/xhtml' 
    xmlns:xsl='http://www.w3.org/1999/XSL/Transform'");
       

In Mozilla/FF, DOM L3 XPath is always available and namespaces are resolved automatically if their scope covers the whole document (i.e. if declared in the root element node). If the namespace's scope is deeper, you must use Sarissa.setXpathNamespaces() to inform browsers (including Mozilla/FF) about them.

Below is an example of using selectNodes and selectSingleNode when Sarissa is available to provide cross browser XPath functionality. For more documentation on these proprietary methods check with the documentation at the MSDN website (http://msdn.microsoft.com). I'm not providing a URL for that as they constantly change their URLs.

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
      <head>
        <title>Sarissa XPath example</title>
        <script type="text/javascript" src="sarissa.js">
        </script>
        <script type="text/javascript" src="sarissa_ieemu_xpath.js">
        </script>
        <script type="text/javascript">
        // <![CDATA[
          function testXpath() {
            // create a DOM document
            var xmlStr = "<?xml version='1.0' encoding='UTF-8'?>"+
            "<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>"+
            "<xsl:output method='xml' version='1.0' encoding='UTF-8' indent='yes'/>"+
            "<xsl:template match='*'></xsl:template><xsl:template match='@*'>"+
            "</xsl:template></xsl:stylesheet>";
            var xmlDoc = (new DomParser()).parseFromString(xmlStr, "text/xml");
            
            // the following two lines are needed for IE
            xmlDoc.setProperty("SelectionNamespaces", "xmlns:xsl='http://www.w3.org/1999/XSL/Transform'");
            xmlDoc.setProperty("SelectionLanguage", "XPath");
            
            // test XPath expressions on the document
            testSelectNodesOn(xmlDoc, "//xsl:template");
            testSelectNodesOn(xmlDoc.documentElement, "//xsl:template");
            testSelectNodesOn((xmlDoc.documentElement.getElementsByTagName("*"))[0], "//xsl:template");
          }
          function testSelectNodesOn(domNode, sXpath) {
            alert("testing selectNodes("+sXpath+") on a "+domNode);
            var objNodeList = domNode.selectNodes(sXpath);
            for(i=0;i<objNodeList.length;i++){
                alert(new XMLSerializer().serializeToString(objNodeList[  i]));
            };
            alert("testing selectSingleNode("+sXpath+") on a "+domNode);
            var oElem = domNode.selectSingleNode(sXpath);
            alert(oElem+"\n"+new XMLSerializer().serializeToString(oElem));
          };
        // ]]>
        </script>
      </head>
    
      <body>
        <button onclick="testXpath()">test xpath</button>
      </body>
    </html>
       
[top]

How to serialize non-DOM objects to XML

You can easily convert any non DOM object to XML using the Sarissa.xmlize method. Sarissa will preserve the structure and naming of the object graph, translating it to an XML tree. Collection items are translated to array-item elements. For an example, the following lines:

    // create an object hierarchy       	
    book.chapters = new Array();
    book.chapters[0] = "Kingdom of Tags";
    book.chapters[1] = "Fall";
    book.chapters[2] = "Final battle";
    book.chapters[3] = "Characters that need to be escaped: << << \"' \"\"\"&&'' < > & ' \" ";
    book.chapters[4] = "Epilogue";
    book.editor = "Manos Batsis";
    var publisher = new Object();
    publisher.name = "Some Publisher";
    book.publisher = publisher;
    
    // serialize to an XML string
    var s = Sarissa.xmlize(book, "book");
    alert("Generated XML:\n"+s)
       

will generate the markup below:

    <book>
      <chapters>
        <array-item key="0">Kingdom of fools</array-item>
        <array-item key="1">Fall</array-item>
        <array-item key="2">Final battle</array-item>
        <array-item key="3">
          Characters that need to be escaped: &lt;&lt; &lt;&lt; 
          &quot;&apos; 
          &quot;&quot;&quot;&amp;&amp;&apos;&apos; 
          &lt; &gt; &amp; &apos; &quot; 
        </array-item>
        <array-item key="4">Epilogue</array-item>
      </chapters>
      <editor>Manos Batsis</editor>
      <publisher>
        <name>Some Publisher</name>
      </publisher>
    </book>
       
[top]