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

Posted

技术标签:

【中文标题】如何使用 XSL 检查是不是存在外部文件?【英文标题】:How do I check for the existence of an external file with XSL?如何使用 XSL 检查是否存在外部文件? 【发布时间】:2011-02-24 10:47:28 【问题描述】:

为此我找到了很多引用 Java 和 C 的示例,但是我如何或可以使用 XSL 检查是否存在外部文件。

首先,我意识到这只是一个 sn-p,但它是一个巨大的样式表的一部分,所以我希望它足以显示我的问题。

    <!-- 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-/>
        <fo:table-column column-/>
        <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-/>

我想要做的是放在一个“if”语句中,围绕$SMSname.jpg 行。那就是:

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

由于“分组”等原因,我使用的是 XSLT 2.0。我希望这是可以做到的。我更希望它是简单的。

与往常一样,提前感谢您的帮助。 罗

【问题讨论】:

好问题 (+1)。简短的回答:目前无法使用纯 XSLT 2.0 完成。长答案和解释:请参阅我的答案。 :) 看起来可以使用 EXPath 扩展 - 文件包 (expath.org/spec/file)... 我已经为自己完成了,请检查我的答案以获得解决方案。 【参考方案1】:

对于任何需要普通 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() 将意味着该文件不存在。

玩得开心!

【讨论】:

【参考方案2】:

如果您仍然想在 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);

【讨论】:

【参考方案3】:

回到 pgfearo 的通知。

提议的文件模块 EXPath 规范将支持文件系统 像这样的函数(规范中的 file:exists())作为标准 XPath 扩展功能。目前还没有一个 XSLT 实现, 但值得一看。

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

file:exists($path as xs:string)

现在工作正常。

【讨论】:

【参考方案4】:

提议的File Module EXPath specification 将支持像这样的文件系统函数(规范中的file:exists())作为标准XPath 扩展函数。目前还没有针对此的 XSLT 实现,但值得关注。

【讨论】:

这对我不起作用,下面是错误:...file:exists($htmlFilePath))... 中第 40 行 char 30 处的 XPath 语法错误:找不到匹配的 1 - 名为 expath.org/ns/fileexists() 的参数函数 它是否依赖于 saxon 版本我使用的是 saxon 8 但不认为会是这种情况。【参考方案5】:

如果您需要检查 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()"/>

参考文献

XML External Entity (XXE) Processing

【讨论】:

【参考方案6】:

如果其他人需要它并且正在使用 fop,我想分享this answer,因为它对我很有用。

我找到了解决办法:

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

它独立于 XSLT 1.0 或 2.0 工作

【讨论】:

【参考方案7】:

对于可能偶然发现这个老问题的其他人,通过将互联网上各种来源的信息拼凑在一起,我想出了这个 XSLT2 函数,它使用 Java 扩展来检查文件是否存在:

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

【讨论】:

使用 PE9.4,我收到错误消息 Error at xsl:sequence on line 32 column 66 of propertize-opf.xslt: XPST0017 XPath syntax error at char 12 on line 32 near ...xists(file:new($absolute-ur...: Cannot find a matching 1-argument function named java.io.Filenew(). For diagnostics on calls to Java methods, use the -TJ command line option or set the Configuration property FeatureKeys.TRACE_EXTERNAL_FUNCTIONS @torazaburo:你确定你将base-uri() 作为第二个参数传递给java:file-exists() 吗?如:&lt;xsl:if test="java:file-exists($filename, base-uri())"&gt; &lt;!-- ... ---&gt; &lt;/xsl:if&gt;。另请注意,此功能仅适用于 XSLT2.0。【参考方案8】:

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

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

【讨论】:

【参考方案9】:

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

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

来自 spec

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

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

在其他情况下,如果对具有相同参数的未解析文本的调用成功,则该函数返回 true;如果对具有相同参数的未解析文本的调用失败并出现不可恢复的动态错误,则该函数返回 false。

注意:

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

引用结束。

【讨论】:

【参考方案10】:

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

我已将之前的答案留在这里,以便您可以追踪不确定性...

我不相信在 XSLT 中使用标准函数可以做到这一点。您可以使用扩展函数来完成,如 here 所述,用于 java。

有unparsed-text-available 函数,但我不确定这是否是标准函数。在Zvon 有一个使用示例。 here 提到 unparsed-text-available 是 xslt 2.0 的一部分,并且在 Saxon 中得到支持。

【讨论】:

以上是关于如何使用 XSL 检查是不是存在外部文件?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 XSL 返回外部 PDF 文件的(总)页数

如何使用 XSLT 测试图像文件是不是存在?

检查包中是不是存在文件

如何使用oozie检查文件是不是存在于HDFS位置?

如何使用 Emacs Lisp 检查文件是不是存在?

如何使用 phpseclib 通过 SFTP 检查上传的文件是不是存在