Manage includes in XSL

∥☆過路亽.° 提交于 2021-02-07 18:12:46

问题


I have a code generating XSL that includes several XSL files. The files are included in order to call templates. There can be the case when one of the files that I need to include does not exist in my file. I could create a dummy file with the same name and an empty template when the original file is missing but I would get a duplicate error when the original file exists.

Bellow is an example:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:date="java.util.Date"                
    xmlns:vector="java.util.Vector"                
    xmlns:math="java.lang.Math"
    xmlns:int="java.lang.Integer"
xmlns:saxon="http://saxon.sf.net/"
    extension-element-prefixes="date vector math int saxon">
  <xsl:include href="file_for_template1.xsl"/> <!-- MIGHT NOT EXIST -->
  <xsl:include href="file_for_template2.xsl"/> <!-- MIGHT NOT EXIST -->
  <xsl:include href="file_for_template3.xsl"/> <!-- MIGHT NOT EXIST -->
  <xsl:output method="xml" 
              version="1.0" 
              encoding="UTF-8" 
              indent="yes"/>
  <xsl:variable name="path" 
                select="concat(base-uri(//Test),'.temp')"/>

  <xsl:template match="/"> 

    <xsl:result-document href="file:/{$path}" method="xml">

      <!-- create the root node -->
      <TEST_GENERATION xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                       xsi:noNamespaceSchemaLocation="test.xsd">

        <xsl:element name="TEST_ELEMENT">
          <!-- SHOULD NOT BE CALLED IF THE FILE DOES NOT EXIST -->
          <xsl:call-template name="template1Call"/>

          <!-- SHOULD NOT BE CALLED IF THE FILE DOES NOT EXIST -->
          <xsl:call-template name="template2Call"/>

          <!-- SHOULD NOT BE CALLED IF THE FILE DOES NOT EXIST -->
          <xsl:call-template name="template3Call"/>

        </xsl:element>

      <!-- end of root node -->
      </TEST_GENERATION>
      <!-- end of document -->
    </xsl:result-document>
  </xsl:template>

回答1:


I wish you had told us more about the problem you are trying to solve, rather than focusing on the difficulties you are having with your chosen approach. If we knew the real requirement, we might be able to suggest better ways of tackling it.

The use-when attribute allows you compile-time control of this kind, enabling you to selectively exclude parts of a stylesheet (including xsl:import/include declarations) based on external conditions. You could try:

<xsl:import href="module1.xsl" 
            use-when="doc-available('module1.xsl')"/>

XSLT 2.0 says that in the context for evaluating use-when expressions there are no available documents, so this will always return false, but this rule changes in XSLT 3.0. In 3.0 you could also pass a static parameter to say whether an xsl:import should be active or not, and reference the static parameter in the use-when attribute.

Your next problem will be that the call-template instructions will fail if the import has been excluded, unless you do something to de-activate these instructions as well. One solution would be to replace them with function calls, which you can conditionally exclude with a test on function-available().

But I'm uneasy about helping you down this road, which is why I didn't answer the question before. I think I might be leading you into a swamp, and that if we knew your real destination, we might be able to suggest a better route to it than the one you are taking.




回答2:


Here's the approach I would use with catalogs (as background information, catalogs are files to can help providing an entity resolver relying on configuration files, so that entities can be effectively resolved against a symbolic name - among other possibilities):

  1. In your input stylesheet, you can modify the imports the following way :

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="2.0" 
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:date="java.util.Date"                
        xmlns:vector="java.util.Vector"                
        xmlns:math="java.lang.Math"
        xmlns:int="java.lang.Integer"
    xmlns:saxon="http://saxon.sf.net/"
        extension-element-prefixes="date vector math int saxon">
      <xsl:include href="cfg:module:file_for_template1.xsl"/> <!-- MIGHT NOT EXIST -->
      <xsl:include href="cfg:module:file_for_template2.xsl"/> <!-- MIGHT NOT EXIST -->
      <xsl:include href="cfg:module:file_for_template3.xsl"/> <!-- MIGHT NOT EXIST -->
    
        ...
    </xsl:stylesheet>
    

The references to files have been changed to a symbolic name - the referenced file itself does not exist.

  1. Here comes in the catalog. You need to first set up a catalog like this so that you will be able to load a "real" file, for the moment, only pointing to the dummy (default) template files.

    <?xml version="1.0" encoding="UTF-8"?>
    <catalog prefer="system" xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
        <uri name="cfg:module:file_for_template1.xsl" uri="path/to/default/file_for_template1.xsl"/>
        <uri name="cfg:module:file_for_template2.xsl" uri="path/to/default/file_for_template2.xsl"/>
        <uri name="cfg:module:file_for_template3.xsl" uri="path/to/default/file_for_template3.xsl"/>
    </catalog>
    

The Saxon documentation - Using XML catalogs will provide you information on how to specify the catalog to be used by the XSL-T engine.

  1. Now when you need to override the template files with the the ones that have been defined in the modules, you will set up a catalog for your module along with the redefining template files, with almost the same entries except that the uri attribute (in the catalog) will point to the template file in the module. I assume that from your code that generates the XSLs, you will also be able to create the appropriate catalog.

  2. you will supply a list of catalogs (semicolon-separated) when invoking your transformation. Here you will typically enter first the "standard" catalog, then the "module" catalog (the order is important). When a same entry is found several times in the catalogs, the latest wins. So if the module catalog you redefine the name "cfg:module:file_for_template1.xsl" so that it points to the module file, it is this file that will be loaded.

Note: the file paths, when you use catalogs, are resolved relatively to the XML catalog.



来源:https://stackoverflow.com/questions/36400013/manage-includes-in-xsl

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!