在XSLT中动态地包含其他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" />

我以不同的方式解决了这个问题,可能对使用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的引用之后):

  1. 使用XSLT从当前样式表生成新的样式表

  2. 将样式表加载为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:includexsl:import)添加到基本XSL文档对象中的ANY节点,从而提供更精细的控制。但是,对所有XSL样式表进行适当的xsl:template构造应该会使插入xsl:include元素更加直接。

相关内容

  • 没有找到相关文章

最新更新