XSLT 2+中实现Dependency Injection的惯用模式探讨
XSLT 中实现依赖注入的惯用模式探讨
本文所指的依赖注入是面向对象中传递代码指针的概念,在函数式编程(FP)中可通过高阶函数实现。在XSLT 2及以上版本中,常见以下几种实现方案:
- 传递函数(遵循函数式编程范式)
- 传递伪“模式”:通过传递显式构造的元素(或嵌入节点结构中的值)并进行匹配
此外还有通过include/import静态注入代码的方式,更类似“模板方法”的静态组合模式。
核心问题:XSLT社区是否有实现依赖注入的惯用模式?
(若能像接口或类型类那样对注入内容进行打包会更理想,伪模式技术似乎可通过将“模式”嵌入其他元素实现,但直接使用函数则不太容易做到)
另外还有第三种方案:返回领域特定语言(DSL)并进行解释,不同上下文采用不同解释方式,类似“流水线”技术,但仅需注入细微逻辑时略显冗余。
通用XML输入
所有方案均基于以下XML输入执行:
<root> <foo/> </root>
方案1:高阶函数(Higher Order Functions)
函数my:apply-function允许注入兼容签名的函数并执行,这是函数式编程的默认技术,示例代码如下:
<xsl:stylesheet version="3.0" xmlns:my="my" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 定义接受函数参数的函数 --> <xsl:function name="my:apply-function" as="xs:integer"> <xsl:param name="input" as="xs:integer"/> <xsl:param name="function" as="function(xs:integer) as xs:integer"/> <xsl:sequence select="$function($input)"/> </xsl:function> <!-- 定义可作为参数传递的示例函数 --> <xsl:function name="my:double" as="xs:integer"> <xsl:param name="value" as="xs:integer"/> <xsl:sequence select="$value * 2"/> </xsl:function> <!-- 主模板 --> <xsl:template match="/"> <result> <!-- 调用my:apply-function并传入my:double作为参数 --> <xsl:variable name="result" select="my:apply-function(5, my:double#1)"/> <doubled-value> <xsl:value-of select="$result"/> </doubled-value> </result> </xsl:template> </xsl:stylesheet>
方案2:伪模式(Pseudo Modes)
该方案将选择逻辑编码在结构中并进行匹配,示例代码如下:
<xsl:stylesheet version="3.0" xmlns:my="my" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template mode="inject" match="Mode[@value = 'double']"> <xsl:param name="value" as="xs:integer"/> <xsl:sequence select="$value * 2"/> </xsl:template> <xsl:template mode="inject" match="Mode[@value = 'treble']"> <xsl:param name="value" as="xs:integer"/> <xsl:sequence select="$value * 3"/> </xsl:template> <!-- 主模板 --> <xsl:template match="/"> <result> <doubled-value> <xsl:variable name="mode"> <Mode value='double'/> </xsl:variable> <xsl:apply-templates mode="inject" select="$mode"> <xsl:with-param name="value" select="5"/> </xsl:apply-templates> </doubled-value> </result> </xsl:template> </xsl:stylesheet>
方案3:DSL/解释器(DSL/Interpreter)
该方案通过my:makeDSL返回XML编码的DSL,再由特定解释器处理,示例代码如下:
<xsl:stylesheet version="3.0" xmlns:my="my" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template mode="inject" match="Mode[@value = 'double']"> <xsl:param name="value" as="xs:integer"/> <xsl:sequence select="$value * 2"/> </xsl:template> <xsl:template mode="inject" match="Mode[@value = 'treble']"> <xsl:param name="value" as="xs:integer"/> <xsl:sequence select="$value * 3"/> </xsl:template> <xsl:template mode="double" match="nop"/> <xsl:template mode="double" match="inject"> <xsl:sequence select="2 * @value"/> </xsl:template> <xsl:template mode="treble" match="nop"/> <xsl:template mode="treble" match="inject"> <xsl:sequence select="3 * @value"/> </xsl:template> <!-- 主模板 --> <xsl:template match="/"> <result> <doubled-value> <xsl:apply-templates mode="double" select="my:makeDSL(5)"/> </doubled-value> </result> </xsl:template> <xsl:function name="my:makeDSL"> <xsl:param name="value"/> <nop/> <inject value="{$value}"/> <nop/> </xsl:function> </xsl:stylesheet>
内容的提问来源于Stack Exchange,提问作者MrD at KookerellaLtd
相关产品推荐
相关产品推荐

