3

I've got an XML file that contains sections that start with a filename:

<madcapfile filename="C:\1\Outputpath\The 7% solution.xlf">

Each section must be saved to an individual file. This is my XSLT:

<xsl:template match="madcapfile">
  <xsl:variable name="file1" select="concat('file:///',@filename)"/>
  <xsl:variable name="file2" select="encode-for-uri($file1)"/>
  <xsl:variable name="file3" select="concat('file:///',replace(@filename,'%','%25'))"/>
  <xsl:result-document method="xml" href="{$file2}">  
    <xsl:apply-templates select="node()"/>
  </xsl:result-document>
</xsl:template>

The variables file1, file2, file3 are my attempts so far. Variable file1 creates files in the correct locations for all files except those with a % in the filename.
Variable file3 creates files in the correct locations for all files, so this is a working solution.

Using variable file2 gives an error: the XSLT processor (Saxon 9.7) tries to write files to

C:\Path-to-XSLT\C:\1\Outputpath\The 7% solution.xlf  

i.e. it looks like encode-for-uri treats its input as a relative path even though it starts with "C:\"
I've also tried adding "file:///" to the start of the path, that does not change the behavior of encode-for-uri.

Is there a way to force encode-for-uri to treat its input as an absolute path?

Daniel Haley
  • 51,389
  • 6
  • 69
  • 95
Hobbes
  • 1,964
  • 3
  • 18
  • 35
  • 2
    The `href` attribute should be a file URI and that means it should have forwards slashes `/` and not backslashes so try whether `concat('file:///', encode-for-uri(replace(@filename, '\\', '/')))` gives you a reliable result. – Martin Honnen Apr 26 '18 at 09:30
  • Yes, that works. So I assume the \ prevents the processor from recognizing the URI? – Hobbes Apr 26 '18 at 09:59
  • 1
    No, the `encode-for-uri` function will escape any backslash. – Martin Honnen Apr 26 '18 at 10:03

2 Answers2

6

There are two issues, the href attributes expects a URI and in a URI the separator character is / and not \ which is used in Windows file paths. Furthermore the use of encode-for-uri escapes any backslash.

So to solve the problem you should replace any backward slash with a forwards slash, then you can use encode-for-uri to escape the percent sign:

concat('file:///', encode-for-uri(replace(@filename, '\\', '/')))
Martin Honnen
  • 160,499
  • 6
  • 90
  • 110
3

On the specific question:

Is there a way to force encode-for-uri to treat its input as an absolute path?

The spec says of fn:encode-for-uri:

Encodes reserved characters in a string that is intended to be used in the path segment of a URI.

So the answer is no: that's not what the function is for. It's not designed to process complete URIs or to understand their syntax; it's designed to process a string that is to be used in constructing the path segment of a URI.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164