How to work around the error "XTDE1500 Cannot write to a URI that has already been read"?
Added by Wolfhart Totschnig over 1 year ago
Hello,
I have an XSLT stylesheet that is supposed to check whether some information in the source document is also contained in another document and, if not, add that information to that other document (i.e., modify the other document). I get the following error from Saxon 12 HE: XTDE1500 Cannot write to a URI that has already been read
I have already encountered this error before, 8 years ago, when using an earlier version of Saxon. I sent an email about it to the old Saxon mailing list:
Michael Kay, in response to that email, explained that Saxon was implementing a rule in the specification here and proposed the following workaround: "contrive two different ways of writing the URI that Saxon fails to recognise as equivalent". Concretely, he proposed to add "./" to one of the two mentions of the URI.
This workaround worked with Saxon 9. But it does not work anymore with Saxon 12; the error message reappeared. So my question is this: Is there a workaround that will work with Saxon 12? In the said response to my email, Michael Kay proposed, as the proper solution, "writing a URIResolver or OutputURIResolver that redirects the URIs". But I think that this is beyond my capabilities and am hoping for a simpler solution or workaround (similar to adding "./").
Thanks in advance for your help!
Replies (12)
Please register to reply
RE: How to work around the error "XTDE1500 Cannot write to a URI that has already been read"? - Added by Vladimir Nesterovsky over 1 year ago
Though, it is against the xslt design of "immutable world" during the processing, you can achieve the goal very simply - just use symlink that aliases the folder with xmls.
RE: How to work around the error "XTDE1500 Cannot write to a URI that has already been read"? - Added by Michael Kay over 1 year ago
You might be able to fool the system by adding a fragment id (#dummy
) or query (?q
) to one of the URIs.
RE: How to work around the error "XTDE1500 Cannot write to a URI that has already been read"? - Added by Wolfhart Totschnig over 1 year ago
Thank you very much for the prompt replies!
As for #dummy
and ?query
, I am sorry to report that the system is not so easily fooled.
As for using "symlink that aliases the folder with xmls", I'm not sure that I understand the suggestion. Is the idea that I point the XSL to a symlink that refers to the XML file to be modified, rather than directly to the XML file? This would be very cumbersome. There are thousands of XML files in my case, and their number is constantly growing. Generating a symlink for each of them would be complicated. I was hoping for a solution that changes only the XSL stylesheet. If there is no such solution, I think that I will prefer to go back to Saxon 9.
RE: How to work around the error "XTDE1500 Cannot write to a URI that has already been read"? - Added by Vladimir Nesterovsky over 1 year ago
Is the idea that I point the XSL to a symlink that refers to the XML file to be modified, rather than directly to the XML file?
Better to have a symlink to a folder rather than to a file.
e.g., if on Windows you have a folder: C:\data\input
then in cmd you can run a command: mklink /D c:\data\output c:\data\input
This way you will have two folders that point to the same content.
Whatever you put into C:\data\input
is seen in the C:\data\output
as well.
From xslt engine point of view these are two unrelated folders.
RE: How to work around the error "XTDE1500 Cannot write to a URI that has already been read"? - Added by Michael Kay over 1 year ago
I'm afraid that when you try to exploit a loophole like this, you always run the risk of locking yourself into the quirks of a particular product release. It would be better to reexamine your logic and think about why you are trying to do something that according to the spec is not permitted.
It would be better to write the result files to a new location, not overwriting the input, and then copy them to the original location if (and only if) the transformation succeeds.
RE: How to work around the error "XTDE1500 Cannot write to a URI that has already been read"? - Added by Wolfhart Totschnig over 1 year ago
Better to have a symlink to a folder rather than to a file
Yes, that makes sense. So I tried, but it didn't work. I replaced <xsl:result-document href="{concat('folder/',.,'.xml')}">
with <xsl:result-document href="{concat('folder_link/',.,'.xml')}">
, where folder_link
is a symlink pointing to folder
, but Saxon is still throwing the same error.
It would be better to reexamine your logic and think about why you are trying to do something that according to the spec is not permitted.
It seems to me that my logic is very simple and, in itself, unobjectionable: 1) read an XML file, 2) check whether it needs to be modified, 3) if so, modify it, overwriting the original file. That this is not possible is, I think, a shortcoming of the spec, not of my logic. I understand that the spec prohibits writing to a file that has already been read because that might, in certain cases, lead to inconsistencies or loops. But what I am trying to do is neither inconsistent nor loopy. That is, it seems to me that the spec is throwing the net too wide here; it shouldn't prohibit what I am trying to do. What you propose (i.e., "to write the result files to a new location, not overwriting the input, and then copy them to the original location if (and only if) the transformation succeeds") seems, to me, more complicated than it should be.
At any rate, thanks a lot for your help! I will choose between implementing your solution and going back to Saxon 9.
RE: How to work around the error "XTDE1500 Cannot write to a URI that has already been read"? - Added by Vladimir Nesterovsky over 1 year ago
where folder_link is a symlink pointing to folder, but Saxon is still throwing the same error.
This is strange. It would be not trivial effort from Saxon to resolve symlinks. And why should it do it?
Can you print with xslt:message resolve-uri(concat('folder/',.,'.xml')) of target files?
RE: How to work around the error "XTDE1500 Cannot write to a URI that has already been read"? - Added by Wolfhart Totschnig about 1 year ago
This is strange. It would be not trivial effort from Saxon to resolve symlinks. And why should it do it?
Could it be that Saxon goes by the inode rather than the URI when judging whether two files are the same?
Can you print with xslt:message resolve-uri(concat('folder/',.,'.xml')) of target files?
The output of resolve-uri(concat('folder/',.,'.xml'))
is file:/path_to_folder/xyz.xml
, whereas the output of resolve-uri(concat('folder_link/',.,'.xml'))
is file:/path_to_folder_link/xyz.xml
. So the URIs are resolved as being different.
RE: How to work around the error "XTDE1500 Cannot write to a URI that has already been read"? - Added by Michael Kay about 1 year ago
resolve-uri() only does a syntactic manipulation of the base and relative URIs as supplied. Saxon, I think, is using File.getCanonicalPath()
in the comparison. I suspect that is resolving symlinks.
RE: How to work around the error "XTDE1500 Cannot write to a URI that has already been read"? - Added by Wolfhart Totschnig about 1 year ago
I decided to go back to Saxon 9, since this is the quickest solution to my problem. I tried Saxon 10 and 11, but the workaround of putting an extra ./
in the URI does not work in these versions either. So it seems that Saxon 9 is the last version with which this works.
Thanks again for your help!
RE: How to work around the error "XTDE1500 Cannot write to a URI that has already been read"? - Added by Michael Kay about 1 year ago
Note that Saxon9 is not one version, but a sequence of 10 major versions each with many minor versions.
Obviously this is a choice that's open to you, but using an old version because your code is dependent on a bug that's been fixed in more recent versions isn't a particularly attractive way forward.
RE: How to work around the error "XTDE1500 Cannot write to a URI that has already been read"? - Added by Wolfhart Totschnig about 1 year ago
using an old version because your code is dependent on a bug that's been fixed in more recent versions isn't a particularly attractive way forward.
I understand that, at some point, I will have to implement the proper solution you suggested earlier (i.e., "write the result files to a new location, not overwriting the input, and then copy them to the original location if (and only if) the transformation succeeds"). But I'll take the quick and easy workaround for the moment. Thanks!
Please register to reply