XSL/JScript difference in behaviour between Visual Studio and IE
Can anyone tell me why the following XSL happily transforms the XML below in IE9, but the same transform fails under all versions of Visual Studio? If I open the XML file in IE 9, it gets transformed and the output is as expected, but if I attempt the same transform on the XML file in Visual Studio (using the 'Start XSLT' button on the toolbar) I get a JScriptException saying function expected on the line
var node = root.nextNode();
The fix seems to be to change the javascript function to do the following instead:
function test(root, attr)
{
root.MoveNext();
var node = root.Current;
return node.Select("breakfast" + attr);
}
But this then fails the XSLT transform in IE! I can't seem to win!
XSL:
<!--<?xml version="1.0"?>-->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:user="urn:custom-scripts">
<msxsl:script language="JScript" implements-prefix="user">
<![CDATA[
function test(开发者_JS百科root, attr)
{
var node = root.nextNode();
return node.selectSingleNode("breakfast" + attr);
}
]]>
</msxsl:script>
<xsl:template match="/">
<HTML>
<BODY STYLE="font-family:Arial, helvetica, sans-serif; font-size:12pt;
background-color:#EEEEEE">
<xsl:value-of select="user:test(., '-menu')"/>
</BODY>
</HTML>
</xsl:template>
</xsl:stylesheet>
Target XML:
<?xml version='1.0'?>
<?xml-stylesheet type="text/xsl" href="simple.xsl" ?>
<breakfast-menu>
<food>
<name>Belgian Waffles</name>
<price>$5.95</price>
<description>Two of our famous Belgian Waffles
with plenty of real maple syrup.</description>
<calories>650</calories>
</food>
<food>
<name>Homestyle Breakfast</name>
<price>$6.95</price>
<description>Two eggs, bacon or sausage, toast,
and our ever-popular hash browns.</description>
<calories>950</calories>
</food>
</breakfast-menu>
Well IE uses MSXML as its XSLT processor (I think IE 9 uses MSXML 6) while Visual Studio uses XslCompiledTransform. The APIs exposed by and used with MSXML and XslCompiledTransform differ vastly so don't expect extension function code written against the MSXML API to work with XslCompiledTransform and the .NET API. See http://msdn.microsoft.com/en-us/library/wxaw5z5e.aspx on how XSLT/XPath types are mapped to .NET types when you use extension functions. In your case you pass in a node-set and a string from XSLT, that maps to an XPathNodeIterator and a String in .NET. Here is a quick attempt to rewrite your extension function for .NET:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:user="urn:custom-scripts">
<msxsl:script language="JScript" implements-prefix="user">
<![CDATA[
function test(nodeIterator, string)
{
nodeIterator.MoveNext();
return nodeIterator.Current.SelectSingleNode("breakfast" + string);
}
]]>
</msxsl:script>
<xsl:template match="/">
<HTML>
<BODY STYLE="font-family:Arial, helvetica, sans-serif; font-size:12pt;
background-color:#EEEEEE">
<xsl:value-of select="user:test(., '-menu')"/>
</BODY>
</HTML>
</xsl:template>
</xsl:stylesheet>
[edit] Oops, I missed that you already found the .NET code yourself and only want to know how to write code against both XSLT processors. That is difficult. What is your target platform and your aim, do you want to write XSLT for IE but develop with VS? Or do you really need to use the same stylesheet within IE and on the .NET platform?
Here is an attempt to write one extension function for both type of processors:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:user="urn:custom-scripts">
<msxsl:script language="JScript" implements-prefix="user">
<![CDATA[
function test(nodeSet, string)
{
if (typeof nodeSet.nextNode !== 'undefined') {
var node = nodeSet.nextNode();
return node.selectSingleNode('breakfast' + string);
}
else if (typeof nodeSet.MoveNext !== 'undefined') {
nodeSet.MoveNext();
return nodeSet.Current.SelectSingleNode("breakfast" + string);
}
}
]]>
</msxsl:script>
<xsl:template match="/">
<HTML>
<BODY STYLE="font-family:Arial, helvetica, sans-serif; font-size:12pt;
background-color:#EEEEEE">
<xsl:value-of select="user:test(., '-menu')"/>
</BODY>
</HTML>
</xsl:template>
</xsl:stylesheet>
You will probably find that the browser embedded into Visual Studio is not IE9. It is most likely to be a version of IE8, or maybe IE7 dependant on which was the stable version when your Visual Studio was released.
I don't really know enough about XLST to explain why it doesn't work, but this may explain the differences in the behaviour you are seeing.
I wonder if this answer on SO will be relevant? IE9 selectSingleNode missing from beta, how to overcome this in JavaScript?
精彩评论