如何使用XSL检查外部文件是否存在?

16

我在stackoverflow上找到了很多关于Java和C的例子,但是我该如何检查XSL中外部文件是否存在,或者能否检查。

首先,我知道这只是一个片段,但它是巨大样式表的一部分,所以我希望它足以展示我的问题。

    <!-- Use this template for Received SMSs -->
<xsl:template name="ReceivedSMS">
    <!-- Set/Declare "SMSname" variable (local, evaluates per instance) -->
    <xsl:variable name="SMSname">
        <xsl:value-of select=" following-sibling::Name"/>
    </xsl:variable>
    <fo:table font-family="Arial Unicode MS" font-size="8pt" text-align="start">
        <fo:table-column column-width=".75in"/>
        <fo:table-column column-width="6.75in"/>
        <fo:table-body>
            <fo:table-row>
                <!-- Cell contains "speakers" icon -->
                <fo:table-cell display-align="after">
                    <fo:block text-align="start">
                        <fo:external-graphic src="../images/{$SMSname}.jpg" content-height="0.6in"/>

我想做的是,在 {$SMSname}.jpg 这一行周围加上一个 "if" 语句。也就是说:

                     <fo:block text-align="start">
                        <xsl:if test="exists( the external file {$SMSname}.jpg)">
                            <fo:external-graphic src="../images/{$SMSname}.jpg" content-height="0.6in"/>                            
                        </xsl:if>
                        <xsl:if test="not(exists( the external file {$SMSname}.jpg))">
                            <fo:external-graphic src="../images/unknown.jpg" content-height="0.6in"/>                            
                        </xsl:if>
                    </fo:block>                       

由于需要进行“分组”等操作,我正在使用XSLT 2.0。我希望这是可以完成的事情。更希望这是一件简单的事情。

像往常一样,非常感谢任何帮助。 LO


好问题(+1)。简短的回答是:目前无法使用纯XSLT 2.0完成。长答案和解释请参见我的答案。 :) - Dimitre Novatchev
看起来使用EXPath扩展 - 文件包(http://expath.org/spec/file)可能是可行的... - potame
我已经为自己完成了这个,检查我的答案以获取解决方案。 - Bharat Darakh
10个回答

12

对于其他可能会偶然发现这个老问题的人,通过在互联网上从各种来源收集信息,我得出了这个使用Java扩展程序检查文件是否存在的XSLT2函数:

<?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:java="http://www.java.com/"
  exclude-result-prefixes="java xs">

  <xsl:function name="java:file-exists" xmlns:file="java.io.File" as="xs:boolean">
    <xsl:param name="file" as="xs:string"/>
    <xsl:param name="base-uri" as="xs:string"/>

    <xsl:variable name="absolute-uri" select="resolve-uri($file, $base-uri)" as="xs:anyURI"/>
    <xsl:sequence select="file:exists(file:new($absolute-uri))"/>
  </xsl:function>

</xsl:stylesheet>
你可以这样使用该函数:
<xsl:if test="java:file-exists($filename, base-uri())">
  <!-- ... -->
</xsl:if>

至少在Saxon 9.1.0.5J中可以使用此方法 — 尚未测试其他XSLT处理器。

注意:如果您要检查存在性的文件是XML文件,并且您正在使用XSLT2,则还可以使用内置的doc-available()函数:

<xsl:if test="doc-available('hello_world.xml')">
  <!-- ... -->
</xsl:if>

1
使用PE9.4,我收到错误消息 propertize-opf.xslt 文件的第32行第66列处的 xsl:sequence 出现错误: XPST0017 XPath 语法错误,位于第32行第12个字符附近 {...xists(file:new($absolute-ur...}: 无法找到名称为 {java.io.File}new() 的匹配的单参数函数。要诊断对 Java 方法的调用,请使用 -TJ 命令行选项或设置 Configuration 属性 FeatureKeys.TRACE_EXTERNAL_FUNCTIONS。 - user663031
@torazaburo:你确定将base-uri()作为第二个参数传递给java:file-exists()吗?像这样:<xsl:if test="java:file-exists($filename, base-uri())"> <!-- ... ---> </xsl:if>。另外,请注意此函数仅适用于XSLT2.0。 - Eero Helenius

11

不,这不能使用XSLT 2.0/XPath 2.0完成。

XSLT 2.0函数unparsed-text-available()仅适用于定位文本文件,即使存在指定URI的文本文件,此函数也可能返回false(),因为它还必须读取文件的内容并检查它是否仅包含允许的字符。

规范中可以看到:

"unparsed-text-available函数确定具有相同参数的对unparsed-text函数的调用是否会返回字符串。

如果第一个参数是一个空序列,则此函数返回false。如果第二个参数是一个空序列,则此函数的行为就像省略了第二个参数一样。

在其他情况下,如果具有相同参数的对unparsed-text的调用将成功,则该函数返回true,如果具有相同参数的对unparsed-text的调用将因不可恢复的动态错误而失败,则返回false。

注意:

这要求unparsed-text-available函数实际上应该尝试读取由URI标识的资源,并检查其是否正确编码并且不包含XML中无效的字符。

引用结束。


3

如果有人需要并且正在使用fop,我想分享这个答案,因为它对我非常有效。

我找到了一个解决方案:

<xsl:when test="fs:exists(fs:new('myfile.html'))" xmlns:fs="java.io.File">
    <!-- do something here... -->
</xsl:when>

它可以独立于XSLT 1.0或2.0工作。


2

编辑:使用unparsed-text-available函数。它是xslt 2.0的一部分,但不是XQuery或独立XPath。

我保留了以前的答案,这样您就可以跟随不确定性的轨迹...

我不相信使用标准函数可以在XSLT中完成此操作。您可以使用扩展函数来完成,如此处所述,对于Java。

有一个unparsed-text-available函数,但我不确定它是否是标准函数。在Zvon上有它的用法示例。未解析的文本可用在这里被提到作为xslt 2.0的一部分,并且在Saxon中得到支持。


2

一份拟议中的File Module EXPath规范将支持文件系统函数,例如规范中的file:exists()作为标准XPath扩展函数。目前还没有XSLT实现,但值得关注。


1
以下是我的错误信息,这个无法运行: XPath 语法错误,位于第40行的第30个字符处,具体如下:{...file:exists($htmlFilePath))...}: 找不到与 {http://expath.org/ns/file}exists() 匹配的一参数函数。 - Bharat Darakh
这与我使用的Saxon版本有关吗?我正在使用Saxon 8,但不认为会是这种情况。 - Bharat Darakh

1

返回pgfearo的通知。

拟议中的File Module EXPath规范将支持文件系统功能,例如标准XPath扩展函数中的file:exists()。目前还没有XSLT实现,但值得关注。

对于需要检查文件是否存在的人。

file:exists($path as xs:string)

现在正常工作。

1
如果您仍然希望在XSLT中进行操作,这里是解决方案,我已经按照下面的说明为自己完成了此操作。
这将无法使用XSLT中的常规java.io.File类。因此,我使用了java.nio.file.Files类。
所需的JARS - servelt.jar w:是我们自己的Java类的命名空间,在其中定义了pathFromURI方法。
代码:
<xsl:variable name="fileURI" select="u:new($absoluteFilePath)" xmlns:u="java:java.net.URI"/>
<xsl:variable name="filePathFromURI" select="w:pathFromURI($fileURI)"/>
<xsl:variable name="fileNotExist" select="not(files:exists($filePathFromURI, /..)) or files:size($filePathFromURI) = 0"/>

public static java.nio.file.Path pathFromURI(java.net.URI uri) throws Exception {
    return java.nio.file.Paths.get(uri);
}

0
如果您需要检查 XML 文件是否存在,请使用外部实体和内联文档类型:
<!DOCTYPE foo [ <!ENTITY bar SYSTEM "baz.xml"> ]>

然后将实体添加到样式表中:

&bar;

处理器将在找不到文件时超时。
如果您知道文件存在但想要动态加载其中一个文件,可以使用concat函数和choose/when块:
<xsl:variable name="page_name">
<xsl:choose>
  <xsl:when test="$page = 1">
    <xsl:value-of select="'page1.xml'"/>
  </xsl:when>
  <xsl:when test="$page = 2">
    <xsl:value-of select="'page2.xml'"/>
  </xsl:when>
  <!--...-->
  <xsl:when test="$page = 9">
    <xsl:value-of select="'page9.xml'"/>
  </xsl:when>
  <xsl:when test="$page = 10">
    <xsl:value-of select="'page10.xml'"/>
  </xsl:when>
  <xsl:otherwise>
    <xsl:value-of select="'page0.xml'"/>
  </xsl:otherwise>
</xsl:choose>
</xsl:variable>

<xsl:variable name="agree" select="document(concat('include/pages/',$page_name))//processing-instruction()"/>

参考资料


0

这不能仅通过标准的XSLT完成,你必须使用扩展函数或一些烦人的解决方法。有两种使用扩展函数的方法:使用标准的java/.NET自定义函数(适用于某些版本的Saxon、AltovaXML等),或使用处理器特定的扩展函数,例如saxon:file-last-modified()/saxon:last-modified()。你可以在这里找到一些示例代码,查找intern:file-exists()。

如果您无法使用扩展函数,则可以在外部生成一个包含有关文件系统信息的XML文件,并将其传递给样式表,或者您可以在SVG中包装二进制图像,然后使用fn:doc-available()。


0

对于任何需要检查文件是否存在的人,您可以使用简单的XSLT解决方案

unparsed-text-available(concat(system-property('user.dir'),'/filename.text'))

或将其封装成一个函数

<xsl:function name="functx:file-exists" xmlns:functx="http://www.functx.com">
    <xsl:param name="path"/>
    <xsl:value-of select="unparsed-text-available(concat(system-property('user.dir'),'/',$path))"/>
</xsl:function>

使用此代码unparsed-text-available(concat(system-property('user.dir'),'/filename.text'))=false()表示文件不存在。

玩得开心!


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