曾经写过一篇 XSLT 文件中使用C#/JScript/VB 自定义函数 怎么用 C#/JScript/VB 在 XSL/XSLT 中自定义函数。那时候原本想直接用 JavaScript 来自定义函数,因为 JavaScript 哪台机器上都能跑,但出了些问题,所以实际中是用的 C# 自定义的 XSLT 函数。
这样的问题无论从哪方面讲都一直回避不了,情况是如果在 JavaScript 定义函数中直接把传入的参数返回是没问题的,但要作任何的处理,或者调用 JS 函数都会失败。XSLT 中的自定义函数,不对参数进行加工处理是没有意义的。比如在 XSLT 中写如下函数:
1 2 3 4 5 6 7 8 9 10 |
<msxsl:script implements-prefix="myfn" language="JavaScript"> function show(blogUrl){ return "".blogUrl; //return blogUrl.split(":")[1]; //如果是对它调用一个方法 } </msxsl> <!-- 在模板中这么调用 --> <xsl:value-of select="myfn:show(blogUrl)"/> |
其实上面那个 show 也是什么事都没做,除非是 return blogUrl; 否则就会报错:
Function 'show' did not return a value, or it returned a value that cannot be converted to an XSL data type.
如果执行的是第二行代码提示的错误将会是:
Microsoft JScript runtime error Object doesn't support this property or method line = 18, col = 3 (line is offset from the s...
出错那时我也没太明白过来是什么原因出错的,因为我也是想当然的认为传入的参数是个字符串,其实不然,若用 typeof(blogUrl) 看下就知道它总是个 object。因为不光是文本节点会作为参数,其他的节点也可能放进来,又因为 C# 是强类型的,因而在用 C# 自定义 XSLT 函数时幸免了。
解决办法是,必须指明类型,即调时的代码的 myfn:show(blogUrl) 必须写成 myfn:show(string(blogUrl))。如果是数字类型就用 number(level)。严格说来 string() 和 number() 并不是在做类型转换,它们都是XPATH 中的函数,即默认为 fn 命名空间下的函数。你也可以试下别的,不过一般我们在自定义函数中处理那些文本或数字的就足矣,笼统来说用 string() 先全部得到对应的字符串就行,只要其中的数据不丢失即可。
最后也完整的补个例子吧,在 xml 中指定一个 xstl 文件,这样就可以直接在 IE 中浏览到转换后的效果,而且也只能在微软的 IE 出成果,大约是用了 xmlns:msxsl="urn:schemas-microsoft-com:xslt" 这样非规范的东西。
text.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?xml version="1.0" encoding="utf-8"?> <?xml-stylesheet type="text/xsl" href="test.xsl"?> <persons> <person> <name>Unmi</name> <level>9</level> <registerTime>8/3/2010 11:17:34</registerTime> <blogUrl>http://unmi.cc</blogUrl> </person> <person> <name>Fantasia</name> <level>5</level> <blogUrl>http://scalaworks.com</blogUrl> <registerTime>9/3/2009 14:17:34</registerTime> </person> </persons> |
test.xsl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:myfn="http://yanbin.blog/fn" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl myfn"> <msxsl:script implements-prefix="myfn" language="JavaScript"> <![CDATA[ function handleTitle(name,level){ //即使是简单的链接,传入前也必须用 string() 指明参数类型; //就是像 return ''.name; 都要指明类型; return name+" : "+level; } function transDate(registerTime){ //return typeof(registerTimte);//如果未指定,则为 object var dateArr = registerTime.split(' '); var darr = dateArr[0].split('/'); return darr[2]+'-'+darr[0]+'-'+darr[1]+" "+dateArr[1]; } function show(blogUrl){ //只有直接返回参数时才无需指定参数类型 return blogUrl; } ]]> </msxsl:script> <xsl:output method="html" indent="yes"/> <xsl:template match="/persons"> <table border="1"> <thead><th>Name</th><th>Register Time</th><th>Blog URL</th></thead> <xsl:apply-templates select="person"/> </table> </xsl:template> <xsl:template match="person"> <tr> <td><xsl:value-of select="myfn:handleTitle(string(name),number(level))"/></td> <td><xsl:value-of select="myfn:transDate(string(registerTime))"/></td> <td><xsl:value-of select="myfn:show(blogUrl)"/></td> </tr> </xsl:template> </xsl:stylesheet> |
参考: 1. XPath、XQuery 以及 XSLT 函数
2. XML XSLT parameters Javascript - how to make it work in Mozilla...
3. W3Schools Forum > XML Forums > XSLT
本文链接 https://yanbin.blog/xslt-javascript-function-parameter/, 来自 隔叶黄莺 Yanbin Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。