我有一个小问题,有没有办法动态包含另一个xsl?例如:
<xsl:variable name="PathToWeb" select="'wewe'"/>
<xsl:include href="http://{$PathToWeb}/html/xsl/head.xsl" />
<xsl:include href="http://{$PathToWeb}/html/xsl/navigation.xsl" />
<xsl:include href="http://{$PathToWeb}/html/xsl/promo.xsl" />
<xsl:include href="http://{$PathToWeb}/html/xsl/3columns.xsl" />
<xsl:include href="http://{$PathToWeb}/html/xsl/footer.xsl" />
我有一个小问题,有没有办法动态包含另一个xsl?例如:
<xsl:variable name="PathToWeb" select="'wewe'"/> <xsl:include href="http://{$PathToWeb}/html/xsl/head.xsl" /> <xsl:include href="http://{$PathToWeb}/html/xsl/navigation.xsl" /> <xsl:include href="http://{$PathToWeb}/html/xsl/promo.xsl" /> <xsl:include href="http://{$PathToWeb}/html/xsl/3columns.xsl" /> <xsl:include href="http://{$PathToWeb}/html/xsl/footer.xsl" />
在href
的<xsl:include>
属性中包含变量引用是非法的。根据W3C XSLT 1.0和XSLT 2.0规范,此属性的值必须是URI引用。
但是,如果在变换开始之前已知$PathToWeb
变量的值,则可以通过多种方式使用它来动态生成样式表表示,其中上面的<xsl:include>
语句包含所需的URI(在将引用替换为$PathToWeb
之后)具有所需的值:
<xsl:include>
元素并将其href
属性设置为所需的值。最后,使用代表样式表的如此修改的XmlDocument调用转换。方法2.已在XPath Visualizer中使用了11年,以动态设置select
属性的精确值,该属性用于选择用户输入的XPath表达式选择的所有节点,并生成表示所有选定和可见的XML文档的HTML文档节点突出显示
我以不同的方式解决了这个问题,对于使用Java和XSLT的人来说可能很有用(这个解决方案特定于使用javax.xml.transform
包的人)。
XSLT变换器工厂允许设置自定义URI解析器。假设您的XSLT看起来像
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" version="4.0" encoding="UTF-8"/>
<xsl:include href="import://stackoverflow.com/xsl"/>
...
URI解析器的resolve
方法将import://stackoverflow.com/xsl
作为href
参数。 import://
可以作为自定义包含的“特殊”标识符方案,因此您可以检测它并创建/返回指向必要文件的javax.xml.transform.Source
。例如:
TransformerFactory tf = TransformerFactory.newInstance();
URIResolver delegate = tf.getURIResolver();
tf.setURIResolver( new CustomURIResolver( delegate ) );
然后,在CustomURIResolver
内:
public Source resolve( String href, String base )
throws TransformerException {
Source result = null;
URI uri = null;
try {
uri = new URI( href );
}
catch( Exception e ) {
throw new TransformerException( e );
}
// The XSLT file has a URI path that allows for a file to be included
// dynamically.
if( "import".equalsIgnoreCase( uri.getScheme() ) &&
"stackoverflow.com".equalsIgnoreCase( uri.getAuthority() ) ) {
result = openTemplate();
}
else {
result = getDelegate().resolve( href, base );
}
return result;
}
添加一个openTemplate()
方法,该方法包含动态确定要打开的XSL文件的逻辑。
你不能做这个。原因很简单:
XSL将首先在编译期间扩展xsl:include,然后再执行其他操作。此时,您的“变量”不知道且无法知道,并且一旦编译,您就无法更改已编译的变量。另外,href是统一资源定位器而不是XPath表达式,因此您不能只扩展其中的变量。
我的2便士值得一个简单(但有效)的替代方案(只提供伪代码用于说明。谨慎行事:)
方法概述:替代解决方案可以包含一个简单的包装脚本(例如shell,bash脚本或其他)来调用主xsl,使用名称xslt模式,主xslt文件,一个简单(空白)静态指定的xslt文件。
在主xsl中,包含一个静态xsl文件,它将调用/加载所有动态包含的xslt。然后,主xsl将以2种模式运行:正常模式(未指定模式),它将加载包含在其自身中的扩展xsl文件,并在静态xls中处理任何输入文件,或执行其预期的任何好东西做。第二种模式,即预处理器模式,用于加载dyanimically指定的xsl实例/文件。此模式将作为主处理运行的预处理器阶段调用。主xslt的处理流程是使用指定的预处理器模式调用它,然后在指示的正常处理模式下再次调用它。
实现提示:为每个xlator定义一个n扩展xslt文件ext_xsl_container,其目的是包含任何扩展xslt。例如
<xsl:stylesheet >
<!-- main xslt -->
<xsl:import href="../xsl/ext_xsl_container.xsl/>
<!--param: list of dynamically specified extension xsl -->
<xsl:param name="extXslUrlList"/>
<!--param:preprocessor mode flag, with default set to false -->
<xsl:param name="preProcModeLoadXslF" select="false()" type="xs:boolean"
<!-- param: path to the staticall included ext_xsl_container: with default value set -->
<xsl:param name="extXslContainerUrl" select="'../xsl/ext_xsl_container.xsl'"/>
<xsl:if test=" ($preProcModeLoadXslF=true())" >
<xsl:call-template name="loadDynamicXsl" mode="preprocess_load_xsl"
</xsl:if>
....
</xsl:stylesheet>
ext_xslt_container样式表将包含任何扩展名xslts。它可以在运行时通过编辑它(作为xml文档)动态更新,为扩展xsl样式表添加include语句。例如
<!-- ext xsl container : ext_xsl_container.xsl-->
<xsl:stylesheet
<xsl:include href="ext_xsl_container.xsl"/>
....
</xsl:stylesheet
使用指定的模式创建一个小模板,比如template_load_ext_xsl,比如mode =“preprocess_load_xsl”,例如
<xsl:template name="loadDynamicXsl" mode="preprocess_load_xsl">
<!-- param: path to the staticall included ext_xsl_container-->
<xsl:param name="extXslContainerUrl"/>
<!--param: list of dynamically specified extension xsl -->
<xsl:param name="extXslUrlList"/>
<!-- step 1, [optional ] open the ext Xsl container file -->
<!-- step 2 [optional] clear contexts of the ext X -- >
<!-- step3 compile a list of include elements, one per each ext Xsl file -->
<!-- step 4 [optional] create a union of the include elements created with the content of the xsl container file : ie append content >
<!-- step 5 : write the union list of incudes to the ext XSL container file -->
<!-- DONE --->
</xsl:template>
该模板将作为参数,ex_xsl_container的名称和扩展xsl文件列表(包括它们的路径),然后它将打开ext_xsl_container文件作为xml文档,添加(要追加的选项,或清除文件并添加新代码) )每个扩展名的语句:xsl,保存文件并退出
接下来,当您在正常执行模式下运行主xsl时,它将包含模板加载Dynamic Xsl,它将包含在运行时指定的扩展xslt文件
创建一个简单的包装器脚本(例如bash或shell脚本),它将接受主xslt的参数,以及一个运行预处理器模式的选项。如果启用了预处理器模式的选项,则脚本将简单地调用主xslt两次,并在第一次运行中启用预处理器模式,然后在正常模式下启用第二次调用
在PHP中,与其他制度一样,使用XSL样式表是一个多步骤的过程:
1)从XSL文件创建SimpleXML或DOMDocument对象。
2)创建XSLTProcessor对象。
3)将XSL文档对象导入处理器对象。
4)对XML数据文件运行转换。
在1)之后,XSL能够在作为步骤3)的一部分编译之前被操纵。在这里,xsl:include元素可以根据需要动态插入根元素。
因此,要动态插入xsl:includes:
1.1)使用Xpath
| getElementById
| getElementsByTagname
检查数据XML是否存在可能需要额外样式表的元素。
1.2)从XSL的XML对象的根元素动态创建xsl:include
元素。
而已。在步骤3),修改的XSL XML对象将被编译,就好像它从一开始就以这种方式构建。
当然,在1.2),来自其他XSL文档对象的任何节点(不仅仅是xsl:include
或xsl:import
)都可以添加到基本XSL文档对象中的任何节点,从而提供更精细的控制。但是,所有XSL样式表的正确xsl:template
构造应该使得插入xsl:include
元素更加直接。