在XSLT中进行文件路径操作

7

我希望生成的输出文件包含指向相对于样式表路径的文件路径。样式表的位置可能会发生变化,我不想使用样式表参数。我的解决方案是获取完整的样式表URI:

<xsl:variable name="stylesheetURI" select="document-uri(document(''))" />

现在我只需要从$stylesheetURI中截取文件名。这启发了我编写XSLT 2.0版本的PHP函数basenamedirname

<xsl:function name="de:basename">
    <xsl:param name="file"></xsl:param>
    <xsl:sequence select="tokenize($file, '/')[last()]" />
</xsl:function>

<xsl:function name="de:dirname">
    <xsl:param name="file"></xsl:param>
    <xsl:sequence 
        select="string-join(tokenize($file, '/')[position() != last()], '/')" />
</xsl:function>

现在我可以在我的模板中做这样的事情:
<img src="{concat(de:dirname($stylesheetURI),'/img/myimage,png')}" />

我的问题是:有没有更好/更快的方法使用本地的XSLT 2.0来完成这个任务?


1
我很喜欢解决这个问题(+1)。请看我的答案,似乎快了25%。 :) - Dimitre Novatchev
1个回答

8

我进行了一些测试(不是很广泛)这些函数。它们似乎比提供的函数快25%。当然,结果取决于字符串长度和合格者数量:

  <xsl:function name="de:basename" as="xs:string">
    <xsl:param name="pfile" as="xs:string"/>
    <xsl:sequence select=
     "de:reverseStr(substring-before(de:reverseStr($pfile), '/'))
     " />
  </xsl:function>

  <xsl:function name="de:dirname" as="xs:string">
    <xsl:param name="pfile" as="xs:string"/>
    <xsl:sequence select=
     "de:reverseStr(substring-after(de:reverseStr($pfile), '/'))
     " />
  </xsl:function>

  <xsl:function name="de:reverseStr" as="xs:string">
    <xsl:param name="pStr" as="xs:string"/>

    <xsl:sequence select=
    "codepoints-to-string(reverse(string-to-codepoints($pStr)))"/>
  </xsl:function>

哇!这可能是因为序列实现(使用tokenize和string-join)比字符串操作具有更高的性能成本吗?但是,string-to-codepoints也返回一个序列,不是吗? - user357812
@Alejandro:tokenize() 做了很多工作——逐个字符扫描并将每个标记放在单独的项目中。而 substring-before() 或 substring-after() 只会扫描到第一个出现的位置。 - Dimitre Novatchev
这对于类Unix路径名非常有效,但我们的XSLT也必须在Windows上运行(使用它们的''路径分隔符)。我将不得不考虑如何通用化此函数,或检测操作系统并相应地更改路径分隔符。 - Cary Millsap
@CaryMillsap,只需添加另一个名为pSeparator的参数,并在Unix情况下传递'/',在Windows情况下传递''。在XPath 3.0中,有用于获取环境变量的标准函数,可以通过这种方式获取操作系统和分隔符。 - Dimitre Novatchev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接