Bug #4289

file:exists() is always faise

Added by Kevon Hayes 6 months ago. Updated 6 months ago.

Start date:
Due date:
% Done:


Legacy ID:
Applies to branch:
9.9, trunk
Fix Committed on Branch:
9.9, trunk
Fixed in Maintenance Release:


I have the following code and test="file:exists()" always returns false no matter if I pass in $file-path1 or $file-path2.

$file-path2 actually renders images when converting this the output of the below transformation into a PDF. So it cannot always be false. Please advise if I am calling this function correctly.

<xsl:stylesheet xmlns:xsl="" xmlns:xd="" xmlns:fo="" xmlns:axf="" xmlns:rev="" xmlns:exsl="" xmlns:ftid="" exclude-result-prefixes="xd" version="3.0" xmlns:file="" xmlns:saxon="" xmlns:pn="http://internal-project-namespace">

<xsl:template match="ftid:Illustration"> fo:block fo:marker <xsl:attribute name="marker-class-name"> <xsl:value-of select="name()"></xsl:value-of> </xsl:attribute> </fo:marker> <xsl:variable name="filename"> xsl:choose <xsl:when test="starts-with(@fileRef, 'G')"> <xsl:value-of select="substring(@fileRef, 2)"/> </xsl:when> xsl:otherwise <xsl:value-of select="@fileRef"/> </xsl:otherwise> </xsl:choose> </xsl:variable>

  <xsl:variable name="file-path1" select="concat('../images/',$filename,'.jpg')"/>
  <xsl:variable name="file-path2" select="concat('../../images/',$filename,'.jpg')"/>

  <!-- Check if file exists-->
    <xsl:when test="file:exists($file-path1)" xmlns:file="">
      <xsl:variable name="file-src" select="$file-path1"/>
      <fo:external-graphic content-width="scale-to-fit"
          <xsl:when test="parent::ftid:ModelGraphic">
            <xsl:attribute name="height">1.5in</xsl:attribute>
            <xsl:attribute name="width">4.5in</xsl:attribute>
      <xsl:variable name="file-src" select="$file-path2"/>
      <fo:external-graphic content-width="scale-to-fit"
          <xsl:when test="parent::ftid:ModelGraphic">
            <xsl:attribute name="height">1.5in</xsl:attribute>
            <xsl:attribute name="width">4.5in</xsl:attribute>

</xsl:template> </xsl:stylesheet>


#1 Updated by John Lumley 6 months ago

The first thing to check is what file:base-dir(), file:current-dir() and file:resolve-path() produce. Most of the issues arise with relative file paths not being relative to where you think they are. That should give some more evidence.

John Lumley

#2 Updated by O'Neil Delpratt 6 months ago


One think to check is directory from which the stylesheet is executed. This I would think is where it starts as the current work directory, since the files are relative to this directory.

Another thing you can look at is running as a test from the command line the following:

Query -qs:"declare namespace file=''; file:exists('filepath-to-file')"

#3 Updated by Kevon Hayes 6 months ago

FYI I cannot use any of the file path based functions in the saxon library or expath > file: functions because an exception occurs with UNC paths: See ticket: 4280. The file based functions was the principal reason why we purchased SAXON PE. The are essentially useless for .NET applications.

So if there is another solution I'm all ears.

#4 Updated by Michael Kay 6 months ago

I think that EXPath/File extension functions should handle UNC paths provide you avoid mixing filenames and URIs.

As John Lumley points out, the problem is likely to be that the relative filename is being interpreted relative to the wrong base. By default, filenames should be interpreted relative to the directory specified in the system property if it exists, or the "current working directory" otherwise. The "current working directory" is a slightly slippery concept on Windows, it basically means the current directory on the current drive, but I don't know how this applies to UNC file naming.

The function file:base-dir is the only function in the EXPath/File module that depends on the static base URI (which is where your problems with UNC files arose). Other functions in the module should, I believe, handle UNC filenames correctly -- though I don't think that the standard test suite actually tests this..

#5 Updated by Kevon Hayes 6 months ago


file:base-dir() blows up whenever I call I go to compile this function. This is a huge detriment to us. If I could solve this issue I would be able to ship product.

FYI, If I use OxygenXML to parse this function it works fine with my XSLT. but as soon as I use it within our .NET application it yields the notorious "Uri contains an authority error". Which is weird because nothing gets passed to the base-dir() function.

#6 Updated by Michael Kay 6 months ago

Do you actually need to use file:base-dir(), and if so why?

Does it "blow up" only if the stylesheet base URI is a UNC location?

What happens if you try resolving relative file names relative to the current working directory instead (this is the default)?

#7 Updated by Kevon Hayes 6 months ago

Technically no, since I can pass a path to the stylesheet as a parameter, but the hopes was to build our image paths from it.

You previously suggested to use http... I cannot change our entire architecture and turn our file server into an HTTP server just to handle this use case. We purchased your library to handle this for us.

Our stylesheet base will always be a UNC path. Opening up the file server the stylesheet resides on to HTTP increase our attack surface and is a greater security risk. As we have highly sensitive data on this server.

The current working directory will not work for us again because all of our files are on a designated file server.

#8 Updated by Michael Kay 6 months ago

  • Status changed from New to In Progress

I think the problem goes away when we fix file:base-dir() as described in bug #4280.

Before closing, I'm going to take a look at whether the documentation of file:base-dir() can be improved, and also at whether we should be using a configuration option in preference to a system property to set the default base directory.

#9 Updated by Michael Kay 6 months ago

  • Tracker changed from Support to Bug
  • Category changed from Saxon extensions to Documentation
  • Status changed from In Progress to Resolved
  • Applies to branch 9.9, trunk added
  • Fix Committed on Branch 9.9, trunk added

In fact there are no problems with the documentation of file:base-dir() -- it does exactly what the EXPath specification says (given the fix in bug #4280).

But we should improve the handling of file:current-dir() (which is used implicitly by functions such as file:exists()). The EXPath specification says that the concept of "current directory" is implementation-defined, so we should define how we implement it.

The implementation (in EXPathFile.toFile(path)) effectively does new File(".").getCanonicalPath(). This is defined in terms of getAbsolutePath()` which according to the Javadoc:

On Microsoft Windows systems, a relative pathname is made absolute by resolving it against the current directory of the drive named by the pathname, if any; if not, it is resolved against the current user directory.

What this means is that there isn't really a single current directory; there is one on each drive, and if the relative file name includes a drive letter, then the current directory for that drive is used; this goes beyond what the EXPath specification suggests.

Furthermore, Saxon uses an undocumented system property to allow the current directory to be set programmatically. This exists essentially to allow testing; the property is set from the test driver.

I have updated the documentation accordingly.

#10 Updated by Debbie Lockett 6 months ago

Updated functions/expath-file/current-dir page in 9.9 documentation online (XML and HTML versions).

#11 Updated by O'Neil Delpratt 6 months ago

  • Status changed from Resolved to Closed
  • % Done changed from 0 to 100
  • Fixed in Maintenance Release added

Bug fix applied in the Saxon maintenance release.

#12 Updated by Kevon Hayes 6 months ago

Great! In hopeful expectation of maintenance release

Please register to edit this issue

Also available in: Atom PDF