Link to home
Start Free TrialLog in
Avatar of yellow1234
yellow1234

asked on

XML XSLT parameters Javascript - how to make it work in Mozilla...

Yes - I ve seen similair questions before and I searched the web but I cannot get it to work in Mozilla -  (works fine in IE with the ActiveXObjects). What I like to achieve is a much more complicated then this - but I ve seen to many times pages and pages of code where a basic example would have done OK... so I narrowed down the code to this:
The basic idea is that through Javascript you set a variable in the xsl document, the xml and xsl is loaded again and the hml document shows the data according to the parameter. I quess my question is what's the ActiveX equivalent in Mozilla and how do i set a parameter then?  Thanks everybody - 3 files below - copy and paste it and you'll see works OK in IE

1. The XML file (four books - Author, Title and Price): books.xml
=========================================
<?xml version='1.0' encoding='ISO-8859-1'?>
<Catalog>
<Book>
<Title>On holiday in Turkey</Title>
<Author>O Arslan</Author>
<Price>20</Price>
</Book>
<Book>
<Title>South Coast of Turkey</Title>
<Author>Peter Jones</Author>
<Price>18</Price>
</Book>
<Book>
<Title>Istanbul and the West Coast</Title>
<Author>John Apple</Author>
<Price>19</Price>
</Book>
<Book>
<Title>The Turkish Black Sea Coast</Title>
<Author>John Deniz</Author>
<Price>19.5</Price>
</Book>
</Catalog>

2.  The XSL file, to display the items sorted by price: sort.xsl
Note the parameter at the top for sorting
=======================================
<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="sortOrder" select="'ascending'" />
 
<xsl:template match="/">
      <xsl:for-each select="Catalog/Book">
                <xsl:sort select="Price" data-type="number" order="{$sortOrder}"/>
            <xsl:call-template name="ShowBooks" />
            </xsl:for-each>
</xsl:template>

<xsl:template name="ShowBooks">
      <xsl:value-of select="Author"/> /
      <xsl:value-of select="Title"/>  / USD
      <xsl:value-of select="Price"/>  <br />
</xsl:template>

</xsl:stylesheet>


3. The HTML file including Javascript. The Javascript
loads the XML and XSL and displays it in a <div>
When changing the select, the Javascript runs again, assigning a value
to the parameter in the xsl file:
=============================================
<html>

<head>
<script language="javascript">

function sortlist(myvalue)   {

    var xslt = new ActiveXObject("Msxml2.XSLTemplate");
    var xslDoc = new ActiveXObject("Msxml2.FreeThreadedDOMDocument");
    var xslProc;
    xslDoc.async = false;
    xslDoc.resolveExternals = false;
    xslDoc.load("sort.xsl");
    xslt.stylesheet = xslDoc;
    var xmlDoc = new ActiveXObject("Msxml2.DOMDocument");
    xmlDoc.async = false;
    xmlDoc.resolveExternals = false;
    xmlDoc.load("books.xml");
    xslProc = xslt.createProcessor();
    xslProc.input = xmlDoc;

    xslProc.addParameter("sortOrder", myvalue);

    xslProc.transform();
    var str;
    str = xslProc.output;
    document.getElementById('books').innerHTML=str;
}

</script>

</head>
<body  onLoad="sortlist('ascending')">
<h2>Books</h2>

<form name='ascdesc'>
Sort price
<select  name ='SortOrder'
onChange="sortlist(ascdesc.SortOrder.options[ascdesc.SortOrder.selectedIndex].value)">
      <option value='ascending' selected>Ascending</option>
      <option value='descending'>Descending</option>
</select>
</form>

<div id='books'></div>

</body>
</html>


=====


Avatar of Gertone (Geert Bormans)
Gertone (Geert Bormans)
Flag of Belgium image

Avatar of yellow1234
yellow1234

ASKER

Gertone,
I had a look again in these pages.
Unfortunately my problem is that there are parts of the solution everywhere - but unfortunately I am not familair enough with this stuff to glue it all together. Also these articles don't  give any examples - should you have one, or should you be able to rewrite my JavaScript file so it runs in Firefox would greatly appreciate it.
the javascript below works both in IE and Mozilla. The condition is that the parameter must be present: this function only changes a parameter.


function SetXSLParam(xsl, paramname, iValue) {
    var i, oNode;
    var oNodeList = xsl.documentElement.childNodes;

    for(i=0;i<oNodeList.length;i++) {
        oNode = xmlNextNode(oNodeList,i);
        if(oNode.nodeName=='xsl:param' && oNode.getAttribute('name')==paramname) {
            oNode.setAttribute('select',iValue);
            break;
        }
    }
}
Oh, you need this function as well, because it is called:

function xmlNextNode(oNodeList,i) {
    var oNode;
    if(oNodeList.snapshotLength) {
        oNode = oNodeList.snapshotItem(i);
    } else {
        try {
            oNode = oNodeList.item(i);
        } catch(e) {
            alert('xmlxsl.js: xmlNextNode() not succesfull');
        }
    }
    return oNode;
}
Hi sybe,
Don't want to be funny but this is only a part for the problem I have - may main challenge is:
Having an empty div in an html document,
fill this div (by Javascript) with the xml data (in an external document - or string), formatted by the xsl document.
I am sure once I ve got this far, I will be able to add the parameter thing.

I saw another question on ee:  (Title: Cross browser XSL Javascript solution?) - there are some links to an example which unfortunately do not work.

Thanks for you contribution - Regards
Ok, I have done that (and it works)

function LoadXMLFile(sURL) {
    var oXML, oRequest;
    try {
        oXML = new ActiveXObject('Msxml2.DOMDocument');
    } catch(e) {oXML = false;}
    if(oXML) {
        //IE load XML document
        oXML.async = false;
        oXML.load(sURL);
        if(oXML.parseError.errorCode) {
            alert('error: ' + oXML.parseError.description);
            return false;
        }
    }
    if(!oXML) {
        //Mozilla load XML document
        try {
            oXML = document.implementation.createDocument("", "", null);
        } catch(e) {oXML = false;}
        if(oXML) {
            oXML.async = false;
            try {
                oXML.load(sURL);
            } catch(e) {oXML = false;}
        }
    }
    if(!oXML) {
        try {
            oRequest = new XMLHttpRequest();
            oRequest.open("GET", sURL, false);
            oRequest.send(null);
            oXML = oRequest.responseXML;
        } catch(e) {oXML = false;}
    }
    return oXML;
}



function ProcessXMLAndXSL(oXML, oXSL) {
    var sHTML = '';
    //IE
    if(window.ActiveXObject) {
        try {
            sHTML = oXML.transformNode(oXSL);
            return sHTML;
        } catch (e) {
            alert('could not transform xml and xsl');
        }
    }
    //Mozilla
    if (document.implementation && document.implementation.createDocument) {
        var oProcessor = new XSLTProcessor();
        oProcessor.importStylesheet(oXSL);
        sHTML = oProcessor.transformToFragment(oXML, document);
        return sHTML;
    }
}


function FillDivWithXMLAndXSL(sXMLURL, sXSLURL, oDiv)
    var oXML = LoadXMLFile(sXMLURL);
    var oXSL = LoadXMLFile(sXSLURL);
    oHTML = ProcessXMLAndXSL(oXML,oXSL);

    if(typeof(oHTML)=='string') {
        //IE
        var oTempDiv = document.createElement('div');
        oTempDiv.innerHTML = oHTML;
        oHTML = oTempDiv.firstChild;
        oDiv.appendChild(oHTML);

        //this seems nonsense, but otherwise the HTML won't show up
        oDiv.innerHTML = oDiv.innerHTML;

        oTempDiv = null;
        window.CollectGarbage();
    } else {
        //Mozilla
        oDiv.appendChild(oHTML);
    }
}
Hi Sybe,
Looks good - thanks much for you efforts - will have a look at it tomorrow - as I have to go out this evening.
Thanks
Hello Sybe,

I tried to apply your script as follows in an html doc:

<html>
<head>
<script language='javascript'>

your script here....

</script>
</head>

<body onload="FillDivWithXMLAndXSL('example1.xml', 'example1.xsl', 'example')">
<div id='example'></div>
</body>
</html>

This gives the following error message in IE:
Object doesn't support this property or method (refers to  oDiv.appendChild(oHTML) in function FillDivWithXMLAndXS)

And the followong in Firefox:
 oDiv.appendChild is not a function. (referring to last line of FillDivWithXMLAndXS)

let me know if I overlook something?

(By the way, a '{' was missing before the function body with FillDivWithXMLAndXS when I copied yur script - I just wacked that in.)

Thanks and regards.






ASKER CERTIFIED SOLUTION
Avatar of sybe
sybe

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
For IE you have to change the code a bit, the result of the XML-XSL transformation is an HTML-fragment with multiple nodes (I never work that way, my transformations always return a single node). That is why the code should be changed a bit:



function FillDivWithXMLAndXSL(sXMLURL, sXSLURL, oDiv) {
    var oXML = LoadXMLFile(sXMLURL);
    var oXSL = LoadXMLFile(sXSLURL);
    oHTML = ProcessXMLAndXSL(oXML,oXSL);

    if(typeof(oHTML)=='string') {
        //IE
        oDiv.innerHTML = oHTML;
    } else {
        //Mozilla
        oDiv.appendChild(oHTML);
    }
}
Works - I am very gratefull thanks!

As a last remark, I am just curious to see that you don't use ActiveXObjects for IE?
In this case where would you be able to set an xsl parameter for the IE section (e.g. simialir to the following for Mozilla:  oProcessor.setParameter(null, "sortOrder", "descending"); ?

Thanks again!




ActiveX is still needed for IE, see this line: "oXML = new ActiveXObject('Msxml2.DOMDocument');"

Of course I have been trying out a lot before I got this working crossbrowser. As you said, I could not find complete examples on internet too, and had to dig through a lot of documentation. But it is worth it, because with this you can use AJAX and combine it with XSL. I think that is the best solution. The bad thing about many AJAX-stuff is that the response from the server must hold HTML-code. And in fact you don't want that. You just want to send the browser new information as XML, and then transform it on the browser.

With this method, the browser can receive just XML, transform it with the XSL that already has been loaded in the browser and pick the updated fragment from the transformation, to replace the current fragment. The only disadvantage is that the initial load of the page will take some time. But that is almost everywhere with Web 2.0 applications.

----
After loading the XSL, the function I posted before (SetXSLParam() ) can change existing parameters.

It should not be too hard to adapt it so that an existing parameter would be changed and a non-existing would be added. But as I see: parameters are only usefull if they have are being used in the XSL, and if they are being used in the XSL, then the parameter has to be set in the XSL. So a usefull parameter is always there already, no need to add one. Except of course if you are generating XSL on the fly, but then you already have a completely different way of working.