Bug #3745
closedfile:path-to-uri() fails or works incorrectly with relative path and UNC
100%
Description
http://www.saxonica.com/documentation/index.html#!functions/expath-file/path-to-uri
Transforms a file system path into a URI with the file:// scheme. If the path is relative, it is first resolved against the current working directory.
So, on Windows, put this file as C:\test dir\path-to-uri.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet exclude-result-prefixes="#all" version="2.0" xmlns:file="http://expath.org/ns/file"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param as="xs:string" name="path" />
<xsl:template name="main">
<xsl:message select="'path=', $path" />
<xsl:variable as="xs:anyURI" name="uri" select="file:path-to-uri($path)" />
<xsl:message select="'uri=', $uri" />
<xsl:sequence select="doc($uri)" />
</xsl:template>
</xsl:stylesheet>
and verify that it works with a very simple relative path:
C:\test dir>dir /b path-to-uri.xsl
path-to-uri.xsl
C:\test dir>java -cp saxon9ee.jar net.sf.saxon.Transform -it:main -t -xsl:path-to-uri.xsl path="path-to-uri.xsl"
Saxon-EE 9.8.0.11J from Saxonica
Java version 1.8.0_161
...
Building tree for file:/C:/test%20dir/path-to-uri.xsl using class net.sf.saxon.tree.tiny.TinyBuilder
...
Looks good.
But file:path-to-uri()
fails or returns unusable URI in the following cases:
Drive relative path¶
C:\test dir>dir /b c:path-to-uri.xsl
path-to-uri.xsl
C:\test dir>java -cp saxon9ee.jar net.sf.saxon.Transform -it:main -t -xsl:path-to-uri.xsl path="c:path-to-uri.xsl"
...
path= c:path-to-uri.xsl
java.io.IOException: The filename, directory name, or volume label syntax is incorrect
at java.io.WinNTFileSystem.canonicalize0(Native Method)
at java.io.WinNTFileSystem.canonicalize(Unknown Source)
at java.io.File.getCanonicalPath(Unknown Source)
at java.io.File.getCanonicalFile(Unknown Source)
at com.saxonica.functions.extfn.EXPathFile.toFile(EXPathFile.java:1169)
at com.saxonica.functions.extfn.EXPathFile.pathToUri(EXPathFile.java:1080)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.saxonica.expr.JavaExtensionFunctionCall.invokeMethod(JavaExtensionFunctionCall.java:828)
at com.saxonica.expr.JavaExtensionFunctionCall.call(JavaExtensionFunctionCall.java:561)
at com.saxonica.expr.JavaExtensionFunctionCall.iterate(JavaExtensionFunctionCall.java:438)
at net.sf.saxon.expr.CardinalityChecker.evaluateItem(CardinalityChecker.java:280)
at net.sf.saxon.expr.parser.ExpressionTool.evaluate(ExpressionTool.java:329)
at net.sf.saxon.expr.LetExpression.eval(LetExpression.java:511)
at net.sf.saxon.expr.LetExpression.processLeavingTail(LetExpression.java:692)
at net.sf.saxon.expr.instruct.Block.processLeavingTail(Block.java:687)
at net.sf.saxon.expr.instruct.Instruction.process(Instruction.java:151)
at com.saxonica.ee.bytecode.ByteCodeCandidate.process(ByteCodeCandidate.java:141)
at net.sf.saxon.expr.instruct.NamedTemplate.expand(NamedTemplate.java:265)
at net.sf.saxon.Controller.callTemplate(Controller.java:2538)
at net.sf.saxon.s9api.Xslt30Transformer.callTemplate(Xslt30Transformer.java:750)
at net.sf.saxon.Transform.processFile(Transform.java:1252)
at net.sf.saxon.Transform.doTransform(Transform.java:782)
at net.sf.saxon.Transform.main(Transform.java:81)
Error at char 17 in xsl:variable/@select on line 7 column 78 of path-to-uri.xsl:
IO error in file path:c:path-to-uri.xsl
IO error in file path:c:path-to-uri.xsl
Rooted relative path¶
C:\test dir>dir /b "\test dir\path-to-uri.xsl"
path-to-uri.xsl
C:\test dir>java -cp saxon9ee.jar net.sf.saxon.Transform -it:main -t -xsl:path-to-uri.xsl path="\test dir\path-to-uri.xsl"
...
path= \test dir\path-to-uri.xsl
uri= file:/C:/test%20dir/test%20dir/path-to-uri.xsl
URIResolver.resolve href="file:/C:/test%20dir/test%20dir/path-to-uri.xsl" base="file:/C:/test%20dir/path-to-uri.xsl"
Using parser com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser
Error at char 4 in xsl:sequence/@select on line 9 column 38 of path-to-uri.xsl:
FODC0002: I/O error reported by XML parser processing
file:/C:/test%20dir/test%20dir/path-to-uri.xsl: C:\test dir\test dir\path-to-uri.xsl (The
system cannot find the path specified)
I/O error reported by XML parser processing file:/C:/test%20dir/test%20dir/path-to-uri.xsl: C:\test dir\test dir\path-to-uri.xsl (The system cannot find the path specified)
UNC path¶
C:\test dir>dir /b "\\localhost\c$\test dir\path-to-uri.xsl"
path-to-uri.xsl
C:\test dir>java -cp saxon9ee.jar net.sf.saxon.Transform -it:main -t -xsl:path-to-uri.xsl path="\\localhost\c$\test dir\path-to-uri.xsl"
...
path= \\localhost\c$\test dir\path-to-uri.xsl
uri= file:/localhost/c$/test%20dir/path-to-uri.xsl
URIResolver.resolve href="file:/localhost/c$/test%20dir/path-to-uri.xsl" base="file:/C:/test%20dir/path-to-uri.xsl"
Using parser com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser
Error at char 4 in xsl:sequence/@select on line 9 column 38 of path-to-uri.xsl:
FODC0002: I/O error reported by XML parser processing
file:/localhost/c$/test%20dir/path-to-uri.xsl: \localhost\c$\test dir\path-to-uri.xsl (The
system cannot find the path specified)
I/O error reported by XML parser processing file:/localhost/c$/test%20dir/path-to-uri.xsl: \localhost\c$\test dir\path-to-uri.xsl (The system cannot find the path specified)
Related issues
Updated by Michael Kay over 6 years ago
Unfortunately there is no definitive spec defining a mapping from file names to URIs.
The approach we use is basically:
return toFile(path).toUri().normalize().toString());
where toFile() is:
File file = new File(path);
if (!file.isAbsolute()) {
return file;
}
boolean maybeURI = path.startsWith("file:");
if (maybeURI) {
URI uri = new URI(path.replaceAll("\\\\", "/"));
return new File(uri.normalize());
} else {
return new File(getWorkingDirectory(), path).getCanonicalFile();
}
This is a literal implementation of what the EXPath spec says, but is probably not what it should say: Windows doesn't simply have a "current working directory", it has one current directory per drive. It looks to me as if we might get better results by resolving relative paths using Java's File.getAbsolutePath() rather than using new File(base, relative). Unfortunately the Saxon EXPath implementation provides the option of setting the current working directory using a system property expath.base.directory, which is mainly useful for testing; because Java doesn't know about this, File.getAbsolutePath() would ignore it. However, we could switch to using File.getAbsolutePath() in cases where expath.base.directory isn't set. We would then have to look again at the test suite and test driver...
Updated by Michael Kay over 6 years ago
- Category set to Saxon extensions
- Status changed from New to In Progress
- Assignee set to Michael Kay
- Priority changed from Low to Normal
I have created a build with this change and have been trying some test cases on a Windows machine.
Most of these examples are now working OK: the exception is UNC filenames. I suspect that the issue is related to https://bugs.java.com/view_bug.do?bug_id=4723726 which indicates that Java's URI.normalize() mangles UNC filenames.
The recommendation in that JDK bug entry is to use File.toPath().toUri() - but that requires JDK 7, and Saxon 9.8 is supported on JDK 6.
I have tried this (using reflection) and it seems to work (falling back to the existing code if you're on JDK 6). That is, the filename //system/path/a.xml is converted to the URI file://system/path/a.xml - I haven't actually tested whether this URI is usable, but if not, that's a different problem.
Updated by Michael Kay over 6 years ago
- Status changed from In Progress to Resolved
- Applies to branch 9.8, trunk added
- Fix Committed on Branch 9.8, trunk added
Patched as described. In the case of UNC filenames, the correct URI is obtained only when JDK 7 or later is used.
Updated by T Hata over 6 years ago
Thanks for the improvement.
Unfortunately I'm afraid Saxon would not like @file://system/path/a.xml@.
Put this as @C:\test\uri.xsl@:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet exclude-result-prefixes="#all" version="2.0" xmlns:file="http://expath.org/ns/file"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param as="xs:string" name="uri" select="static-base-uri()" />
<xsl:template name="main">
<xsl:message select="'$uri=', $uri" />
<xsl:sequence select="doc($uri)" />
</xsl:template>
</xsl:stylesheet>
C:\>dir /b /s \\localhost\c$\test\uri.xsl
\\localhost\c$\test\uri.xsl
doc()
works with @file:////localhost/...@:
C:\>java -cp saxon9ee.jar net.sf.saxon.Transform -it:main -t -xsl:\\localhost\c$\test\uri.xsl
...
$uri= file:////localhost/c$/test/uri.xsl
URIResolver.resolve href="file:////localhost/c$/test/uri.xsl" base="file:////localhost/c$/test/uri.xsl"
Using parser com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser
Building tree for file:////localhost/c$/test/uri.xsl using class net.sf.saxon.tree.tiny.TinyBuilder
But not with @file://localhost/...@:
C:\>java -cp saxon9ee.jar net.sf.saxon.Transform -it:main -t -xsl:\\localhost\c$\test\uri.xsl uri=file://localhost/c$/test/uri.xsl
...
$uri= file://localhost/c$/test/uri.xsl
URIResolver.resolve href="file://localhost/c$/test/uri.xsl" base="file:////localhost/c$/test/uri.xsl"
Using parser com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser
Error at char 4 in xsl:sequence/@select on line 7 column 38 of uri.xsl:
FODC0002: I/O error reported by XML parser processing file://localhost/c$/test/uri.xsl:
\c$\test\uri.xsl (The system cannot find the path specified)
I/O error reported by XML parser processing file://localhost/c$/test/uri.xsl: \c$\test\uri.xsl (The system cannot find the path specified)
Updated by Michael Kay over 6 years ago
According to https://stackoverflow.com/questions/1546419/convert-file-path-to-a-file-uri, the name "localhost" is magic. Do your conclusions also apply to a real server name?
Updated by T Hata over 6 years ago
file://real-server-name/
and file://127.0.0.1/
worked.
Looks like file://localhost/
and file://%3F/
do not work. (@file:////localhost/@ and file:////%3F/
work.) I think that is acceptable for now.
Updated by O'Neil Delpratt over 6 years ago
- Status changed from Resolved to Closed
- % Done changed from 0 to 100
- Fixed in Maintenance Release 9.8.0.12 added
Bug fix applied in the Saxon 9.8.0.12 maintenance release.
Updated by Michael Kay over 5 years ago
- Precedes Bug #4280: Failure in file:base-dir(): "URI has an authority component" added
Updated by Michael Kay over 5 years ago
The investigation of bug #4280 revealed new insights on how Java and .NET handle UNC filenames (differently) in the "file" URI scheme. Most operations work (on both platforms), but Java's URI.normalize()
is not usable with either representation.
Please register to edit this issue