在XSLT中动态包含其他XSL文件

问题描述 投票:8回答:5

我有一个小问题,有没有办法动态包含另一个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" />
xslt markup xslt-1.0
5个回答
5
投票

我有一个小问题,有没有办法动态包含另一个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之后)具有所需的值:

  1. 使用XSLT从当前样式表生成新样式表。
  2. 将样式表加载为XmlDocument对象。然后找到相应的<xsl:include>元素并将其href属性设置为所需的值。最后,使用代表样式表的如此修改的XmlDocument调用转换。

方法2.已在XPath Visualizer中使用了11年,以动态设置select属性的精确值,该属性用于选择用户输入的XPath表达式选择的所有节点,并生成表示所有选定和可见的XML文档的HTML文档节点突出显示


5
投票

我以不同的方式解决了这个问题,对于使用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文件的逻辑。


2
投票

你不能做这个。原因很简单:

XSL将首先在编译期间扩展xsl:include,然后再执行其他操作。此时,您的“变量”不知道且无法知道,并且一旦编译,您就无法更改已编译的变量。另外,href是统一资源定位器而不是XPath表达式,因此您不能只扩展其中的变量。


0
投票

我的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两次,并在第一次运行中启用预处理器模式,然后在正常模式下启用第二次调用


0
投票

在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:includexsl:import)都可以添加到基本XSL文档对象中的任何节点,从而提供更精细的控制。但是,所有XSL样式表的正确xsl:template构造应该使得插入xsl:include元素更加直接。

© www.soinside.com 2019 - 2024. All rights reserved.