我有一个小问题,是否有一种方法可以动态地包含另一个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" />
我以不同的方式解决了这个问题,可能对使用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 ) );
Then, inside 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: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:include>
的href
属性中有变量引用是非法的。根据W3C XSLT 1.0和XSLT 2.0规范,该属性的值必须是URI引用。
但是,如果在转换开始之前已知$PathToWeb
变量的值,则可以通过多种方式使用它来动态地生成样式表表示,其中上面的<xsl:include>
语句包含所需的uri(在用所需的值替换对$PathToWeb
的引用之后):
-
使用XSLT从当前样式表生成新的样式表
-
将样式表加载为XmlDocument对象。然后找到相应的
<xsl:include>
元素,并将它们的href
属性设置为所需的值。最后,使用表示样式表的修改后的XmlDocument调用转换。
方法2。已在XPath Visualizer中使用了11年,用于动态设置select
属性的确切值,该属性用于选择用户输入的XPath表达式所选择的所有节点,并生成一个HTML文档,其中突出显示所有选中的和可见的节点,表示XML文档。
你不能这么做。原因很简单:
XSL将首先在编译期间展开XSL:include,然后再执行其他操作。在这一点上,你的"变量"是不知道的,不能被知道,你不能改变编译后的转换,一旦它编译。此外,href是统一资源定位符,而不是XPath表达式,因此不能在其中展开变量。
我在一个简单(但有效)的替代方案上花了2便士(仅提供了用于说明的伪代码)。小心行事:)
方法概述:另一种解决方案可以包括一个简单的包装脚本(如shell、bash脚本或其他)来调用主xsl,使用名称xslt模式,主xslt文件,一个简单的(空白)静态指定的xslt文件。
在主xsl中,包含一个静态xsl文件,它将调用/加载所有动态包含的xslt。主xsl将在两种模式下运行:普通模式(未指定模式),它将加载包含在自身和静态xsl中的扩展xsl文件,并处理任何输入文件,或者做任何它想做的好事情。第二种模式,预处理器模式,将用于加载动态指定的xsl实例/文件。此模式将作为主处理运行的预处理器阶段调用。主xslt的处理流程是使用指定的预处理器模式调用它,然后使用指定的正常处理模式再次调用它。
实现提示:为每个xlator定义一个扩展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样式表将包含任何扩展xslt。通过编辑它(作为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时,它将包含模板loadddynamicxsl,它将返回包含在运行时指定的扩展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文档对象的ANY节点(不仅仅是xsl:include
或xsl:import
)添加到基本XSL文档对象中的ANY节点,从而提供更精细的控制。但是,对所有XSL样式表进行适当的xsl:template
构造应该会使插入xsl:include
元素更加直接。