Link to home
Start Free TrialLog in
Avatar of zc2
zc2Flag for United States of America

asked on

Safari's transformToDocument() and xsl:import

Is it possible to make Safari browser's XSLTProcessor properly execute the transformToDocument() method when the XSLT template has an xsl:import element? In my case the method returns nothing.  
I have attached a HTML snippet  for testing as well as  the XML and XSLT files it refers to.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
 
<SCRIPT type='text/javascript'>
 
function testXSL() {
   try {
        var req = new XMLHttpRequest();
        req.open("GET", "empty.xsl", false);
        req.send(null);
        var  xsl = req.responseXML;
        if( !xsl ) {
            alert("Unable to load xsl!");
            return false;
        }
        alert(new XMLSerializer().serializeToString( xsl.documentElement ));
 
        var xsl_processor = new XSLTProcessor();
        xsl_processor.importStylesheet( xsl );
 
 
        req.open("GET", "empty.xml", false);
        req.send(null);
        var  xml = req.responseXML;
        if( !xml ) {
            alert("Unable to load xml!");
            return false;
        }
 
 
        var result_doc = xsl_processor.transformToDocument( xml );
        if( !result_doc ) {
            alert("Unable to transform!");
            return false;
        }
        alert(new XMLSerializer().serializeToString(result_doc.documentElement));
    }
    catch( e ) {
        alert("XSLT error: "+e.message + "(" + e + ")");
        return false;
    }
}
 
//</SCRIPT>
</HEAD>
<BODY>
<input type="button" value="test XSL" onclick="testXSL();"/>
</BODY>
</HTML>
 
--- empty.xsl ---
 
<?xml version="1.0"?>
<xsl:stylesheet 
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
	version="1.0">
	<xsl:import href="utility_template.xsl"/>
</xsl:stylesheet>
 
--- empty.xml ---
 
<root></root>

Open in new window

Avatar of abel
abel
Flag of Netherlands image

Quite recently, a report of a bug/issue with xsl:include was posted on the Google Chrome site: http://code.google.com/p/chromium/issues/detail?id=8441. Since Chrome uses the same processor as Safari, it seems related. According to the issuer, the problem is a permissions/security issue which blocks the URL from being retrieved.

Quite a while ago I posted a fix for a similar issue for the Sarissa cross-browser XSLT library, which was related to relative paths and *.js files, where IE and other browsers interpreted the base path differently. If a path problem may be the cause of your issue, you can test that by applying an absolute path to see if that makes a difference.

-- Abel --
Avatar of zc2

ASKER

No, absolute path brings the same result.
Is there any possible workaround?
that's where the problem comes in. On the XSLT list this matter has been the subject of debate a couple of times. The problem is, you cannot simply create some function that combines the stylesheets and then runs the complete stylesheet. That is because of the import precedence complexities (they would fade away as soon as you combine them) and add to that the apply-imports calls, which wouldn't mean much anymore.

Unfortunately it has been found that expressing xsl:import in one XSLT is actually impossible, apart from the most trivial cases: parse your stylesheet and apply an <xsl:copy-of select="document(xls-import/@href)/*/xsl:template" /> (use an xsl ns alias) to every xsl:import statement, recursively. The resulting XSLT XML document can then be used for XSLT processing. But you'll loose much of the xsl:import functionality this way.

If I have some time tomorrow I'll try to dig up some comments of Chrome/Safari developers on the subject. Maybe they've some timeline for a fix, but so far I haven't seen much in that direction.

-- Abel --
Avatar of zc2

ASKER

Thank you for the advise. But, not matter how hard I try, the document() function returns an empty document.
just a question intermittently, but are the urls relative to the current url? Are they higher or lower up the path hierarchy? Can you give an example of your urls from the main .html (or .jsp/.aspx), the .js holding the XSLT transform code (if any) and the *.xslt files (incl the imported ones)?

It looks very much like a similar issue that I had before, it would help if I knew how exactly you are building the xslt and from where (and yes, I saw the code above).
Avatar of zc2

ASKER

<a>(((((<item>2222</item>))))</a>
xsl-document.tar.txt
Avatar of zc2

ASKER

I'm sorry, sent the last comment before actually write it.

What you see in the previous comment is the result I see in a firefox browser.
In a webkit based browser (Chrome, Safari 4) the result is only

<a>((((())))</a>

The attached file in the previous comment is a .tar archive with the files I use for the testing.
testxsl_doc.htm -  main file, open it in the browser, then click the button.
doc.xsl - an XSLT using the document() function
empty.xml - empty xml which document() tries to access
0.xml - another empty xml to make the transformation with.
I started out getting other results, but now I'm on the same page as you. Just for argument's sake, I put some screenshots here to make sure we all agree on the differences.

ScreenShot209.png
ScreenShot210.png
ScreenShot208.png
ScreenShot207.png
ScreenShot206.png
ASKER CERTIFIED SOLUTION
Avatar of abel
abel
Flag of Netherlands image

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
Avatar of zc2

ASKER

Thank you for the great work you did. It seems I need just to disable the ajax functionality for that kind of browsers at least for a while.
If there any news how to make the xsl:import work, please let me know, I'll very appreciate that.
glad I could be of some help :)

See the second post here: http://ajaxandxml.blogspot.com/search/label/Chrome which is about disabling XSLT for chrome.

I just downloaded the Chrome source to see why it is not executing the code above. I'll let you know if I find something useful. I checked the (advanced) security settings and widened them, but that did not yield any results.
Avatar of zc2

ASKER

Thank you. But is there simpler way to detect a webkit based browser?
if (navigator.userAgent.toLowerCase().indexOf('webkit')!=-1) alert('Go upgrade to an XSLT supporting browser')
Avatar of zc2

ASKER

:)
Thank you.
Hi zc2,

I know you closed this question, but you asked me to update if I knew something more. These days I played a bit with the source code of Chrome (quite a bit of a piece of code, btw) and tried to find the point of error and/or a workaround.

Unfortunately, the place in the code where XSLT is resolving external documents (id. for xsl:import/include) does never run. It uses an if-statement that is supposed to check the validity of the URL, but because of negligence of the programmers, they forgot to give it a context-frame, which is necessary for that piece of code to return true (i.e., valid).

End of the story: it is a bug, and quite a major one. They do have all the code there to make it work, but due to this bug it doesn't work. I changed the code a bit and managed to get it working without too much efforts. Here's a screenshot of a beta-build with modified source that runs your code correctly:

ScreenShot213.png
Avatar of zc2

ASKER

Great job! You're really a genius!!
Did you submit the issue to developers?
If they going to fix it both in Safari and Chromium, I'm willing to wait until the new version will come.
Thank you again very much!
I don't know enough of the intricacies involved to know whether bullying with these settings and code might have some waterfall effect on something else. Of course I can point them to the problem (and I will) and a possible direction for the solution. The only related bug issue that I could find so far is currently this one, and it only touches at the issue.

-- Abel --
Avatar of zc2

ASKER

I hope they will respond and fix the bug.