Dynamically include other XSL files in XSLT

I have a little problem, is there a way to dynamically enable another xsl? For example:

<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" /> 
+8
source share
5 answers

I have a little problem, is there a way to dynamically enable another XSL? For example:

 <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" /> 

You cannot have a variable reference in the href <xsl:include> attribute . According to the W3C specifications XSLT 1.0 and XSLT 2.0, the value of this attribute must be a URI reference.

However, if the value of the $PathToWeb variable is known before the start of the conversion, it can be used in several ways to dynamically present the presentation of style sheets in which the above <xsl:include> statements contain wish URIs (after substituting the $PathToWeb with the required value:

  • Create a new stylesheet from the current using XSLT.

  • Load the stylesheet as an XmlDocument object . Then find the appropriate <xsl:include> elements and set their href attributes to the desired values. Finally, invoke the transformation using the so-modified XmlDocument, which represents a stylesheet.

Method 2 has been used for 11 years in XPath Visualizer to dynamically set the exact value of the select attribute to select all the nodes that a custom XPath expression selects and to create an HTML document representing an XML document with selected and visible nodes.

+5
source

I solved this problem in a different way, it can be useful for those who work with Java and XSLT (this solution is typical for people using the javax.xml.transform package).

The XSLT factory transformer allows you to configure a custom URI resolver. Say if your XSLT looks like

 <?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"/> ... 

The resolver URI resolver method will receive import://stackoverflow.com/xsl as the href parameter. import:// can serve as a "special" identifier scheme for custom includes, so you can detect it and create / return javax.xml.transform.Source that points to the necessary file. For example:

 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; } 

Add the openTemplate() method, which includes logic to dynamically determine which XSL file to open.

+5
source

You cannot do this. The reasons are simple:

XSL will first extend xsl: include at compile time before it does anything else. At this point, your β€œvariable” does not know and cannot be known, and you cannot change the compiled transformation after compiling it. In addition, href is a Uniform Resource Locator, not an XPath expression, so you cannot just expand a variable in it.

+2
source

In PHP, as in other modes, using the XSL stylesheet is a multi-step process:

1) Create a SimpleXML or DOMDocument object from an XSL file.

2) Create an XSLTProcessor object.

3) Import the XSL document object into the processor object.

4) Run the conversion of the XML data file.

After 1) XSL can be manipulated before compilation as part of step 3). This is where xsl: include elements can be dynamically inserted from the root element as needed.

Therefore, for xsl: includes dynamic insertion:

1.1) Use Xpath | getElementById | getElementsByTagname to check XML data for elements for which you may need additional style sheets.

1.2) Dynamically create xsl:include elements from the root element of an XSL XML object.

It. In step 3), the modified XSL XML object will be compiled as if it were built in this way from the very beginning.

Of course, at level 1.2) ANY nodes (not only xsl:include or xsl:import ) from other objects of the XSL document can be added to ANY nodes in the base object of the XSL document, which provides more precise control. However, the correct xsl:template construct for all XSL stylesheets should greatly simplify the simple insertion of xsl:include elements.

0
source

My 2 pence is worth a simple (but effective) alternative (psuedocode only for illustration). Be careful:)

Brief description of the approach: An alternative solution may consist of a simple shell script (for example, a shell, bash script or another) to call the main xsl, use the names of xslt modes, the main xslt file, a simple (empty) statically defined xslt file.

In the main xsl, include a static xsl file that will call / load all dynamically included xslt. Then the main xsl will work in two modes: in normal mode (unspecified mode), where it will load the xsl extension files included in itself and in static xls, and process any input files, or do what has ever been useful for doing it. The second mode, preprocessor mode, will be designed to load dyanimically specified xsl / file instances. This mode will be called as a preprocessor stage for the main processing run. The process thread for the main xslt would consist of calling it with the specified preprocessor mode, and then calling it again with the specified normal operating mode.

Implementation recommendations: For each xlator, define the xslt n ext_xsl_container extension file, the purpose of which is to include any xslt extension. eg,

  <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> 

The ext_xslt_container stylesheet will contain any xslts extension. It can be dynamically updated at run time by editing it (as an XML document) by adding an include statement for xsl extension stylesheets. eg,

  <!-- ext xsl container : ext_xsl_container.xsl--> <xsl:stylesheet <xsl:include href="ext_xsl_container.xsl"/> .... </xsl:stylesheet 

Create a small template, say template_load_ext_xsl, with the mode assigned, say mode = "preprocess_load_xsl" for example

 <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> 

The template will take as arguments the name ex_xsl_container and the list of xsl extension files (including their paths) it will open the ext_xsl_container file as an XML document, add (options for adding or cleaning the file and adding new code) for each extension: xsl, save the file and will come out

Next, when you start the main xsl in normal runtime, it will include the loadDynamicXsl template, which will include the xslt extension files specified at runtime

Create a simple shell script (for example, bash or shell script)), which will take the arguments for the main xslt and the ability to run the preprocessor. The script will simply call the main xslt twice if the option for preprocessor mode is turned on and turns on preprocessor mode on first run, and then a second call in normal mode

0
source

All Articles