Alternative for using ../../

2019-08-09 10:46发布

问题:

In my current configuration, I have an include statement as such:

<xsl:include href="../../../specialdata/anotherfolder/template.xslt"/>

How can I make an expression here that says:"traverse up the path until you're at the level where also the folder 'specialdata' is"?

回答1:

The href attribute is simply a URL, in your case a relative URL. I don't think URLs have some way of searching for a certain folder.



回答2:

No. There's no way to do that with relative URIs.

You might though find it handy to do something like:

<xsl:include href="/specialdata/anotherfolder/template.xslt"/>

Or

<xsl:include href="/templates/specialdata/anotherfolder/template.xslt"/>

Or something else that starts at the root of the site the templates found on, rather than starting at the current template.

Or that may be much less convenient, depending on how the templates' location is structured, whether they are used as a group at different locations, etc.



回答3:

I don't (quite) agree with the previous answers, there are ways to achieve this, both standard (with XSLT 3.0) and processor-dependent (using a UriResolver) for older processors.

With XSLT 1.0 and 2.0:

Typically, XSLT processors allow you to return something from any location based on the href attribute by using a UriResolver. It depends on the processor you use on how to create, compile and configure such a component. Usually it means using the native language (Java, C++, C#) to implement an interface and to configure the transformation to use this as an alternative to the default UriResolver.

Inside the code you write for the UriResolver, you can do whatever you want, including traversing different parent directories for checking whether a partial URI matches.

Remember that XSLT does not take a URL here, it takes a URI. It's location is not predefined by the URI, in fact, the URI is said to have a mapping to a physical location, which can be a file, an in-memory XML tree, a database field etc.

With XSLT 3.0, using powerful shadow attributes

Alternatively, in XSLT 3.0 there is a cross-platform solution with shadow attributes (attributes starting with an underscore that can take an attribute value template that is processed during the static evaluation phase).

One limitation of shadow attributes is that it cannot call stylesheet functions (the ones you declare with xsl:function), but any XPath function can be called and every legal XPath expression is also a legal static expression.

The following works in XSLT 3.0, provided that the "statically available documents" (which is possible restricted by your processor) include the documents on the local path:

<xsl:variable name="include" 
    static="yes" 
    select=" 'specialdata/anotherfolder/template.xslt' " />

<!-- note the underscore -->
<xsl:include _href="{
    ('../', '../../', '../../../') 
    [document-available(. || $include)][1]
    || $include }" />

The snippet above works as follows:

  • create a static variable, which must be declared prior to its use, containing the known part of the path
  • create a sequence of relative parent paths
  • let the predicate return true when the path contains the template.xslt
  • return the first found
  • concatenate (using the XSLT 3.0 || operator) the dotted path to the $include variable
  • result is a string containing an existing path (or empty sequence otherwise, which will yield an error) to the include-file
  • the result of the shadow attribute becomes the value of the real attribute href.

Note, without extension functions it is not possible to check for a directory to exist, but in your case, it matters little, because if the directory exists, the call only makes sense if also the file exists, so we can just as well check the whole path.

Known XSLT 3.0 processors that support shadow attributes are Exselt (.NET) and Saxon (primarily Java). Other XSLT 3.0 processors like XMLPrime and Altova Raptor (both very partial XSLT 3.0 support) do not support shadow attributes (yet).



标签: xslt uri