Reputation: 349
Yesterday I have already asked a question about Saxon and XSLT but I still have not solved my problem fully. Short about what I want to achieve:
As first input File I have an html file with following code:
`
<h1>Use_Cases</h1>
<table border="1">
<tr>
<td>file_name</td>
<td>function1()</td>
<td>function2()</td>
<td>function3()</td>
<td>function4()</td>
<td></td>
</tr>
<tr>
<td>test1</td>
<td>a+a;</td>
<td>b+b;</td>
<td>c+c;</td>
<td>d+d;</td>
<td></td>
</tr>
<tr>
<td>test2</td>
<td>a+a;</td>
<td>b+b;</td>
<td>c+c;</td>
<td>d+d;</td>
<td></td>
</tr>```
`
function1(){
a+a;}
function2(){
b+b;}
function3(){
c+c;}
I have written such code to transform my html file on base of last asked question:
<xsl:template match="/html/body/table" >
<xsl:for-each select="/tr/td[1]">
<xsl:variable name="file_name" select="../tr/td[1]"/>
<xsl:result-document href="{$file_name}.cpp" method="text">
<xsl:apply-templates select="html/body/table/tr[1]/td[position() > 1 and position() < 6]"/>
</xsl:result-document>
</xsl:for-each>
</xsl:template>
<xsl:template match="td">
<xsl:param name="pos" select="position()"/>
<xsl:value-of select="., '{', ../following-sibling::tr[1]/td[$pos + 1], '}'" separator=" "/>
<xsl:text> </xsl:text>
</xsl:template>
My problem is that Saxon does not tell me about any mistake or error it just ends working and does not create any file. I have also tried to procced my code in online IDE https://xsltfiddle.liberty-development.net/ but it tells me that:
xsl:result-document is disabled when extension functions are disabled
What problem I have? Why Saxon ends working without creating any file(and without errors)?
Thanks In Advance.
Upvotes: 1
Views: 150
Reputation: 163322
A couple of observations:
(1)
<xsl:template match="/html/body/table" >
<xsl:for-each select="/tr/td[1]">
This is clearly wrong. The "/tr/td" forces selection to be from the root of the document, not from the current element. For a relative selection you want `select="tr/td[1]".
Similarly, when you do select="html/body...."
you're doing a relative selection from the wrong context. To get path expressions right, it's essential to understand how different instructions change the context.
(2) xsl:result-document is disabled when extension functions are disabled
This is because xsltfiddle has to handle untrusted stylesheets, and it can't permit untrusted stylesheets to write documents into arbitrary locations on the server filestore. You won't get this problem if you run (with default options) on your own server or laptop.
(3) Saxon does not tell me about any mistake or error it just ends working and does not create any file
Yes, it's an unfortunate effect of a dynamic language like XSLT that an incorrect path expression tends to have no symptoms other than failing to select anything, and therefore failing to execute some of your code (e.g. the body of an xsl:for-each). Schema-aware XSLT was designed to address that problem, but it adds complexity so only a minority of users actually exploit it - though in my experience, if you make the up-front effort, it can give good productivity rewards when it comes to subsequent maintenance. With schema-aware XSLT, properly used, there's a good chance that incorrect path expressions will result in a compile time error. The problem is that the people who need this most are beginners, and beginners naturally don't want any extra complexity.
Upvotes: 1
Reputation: 167516
The answer I posted as a response to your previous question is at https://xsltfiddle.liberty-development.net/bwe3c5/1 and has the code
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:strip-space elements="*"/>
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:apply-templates select="html/body/table/tr[1]/td[position() > 1 and position() < 6]"/>
</xsl:template>
<xsl:template match="td">
<xsl:param name="pos" select="position()"/>
<xsl:value-of select="., '{', ../following-sibling::tr[1]/td[$pos + 1], '}'" separator=" "/>
<xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
If you run Saxon from the command line you could just use -o:file.text
for a particular output file name; if you need to do it in the XSLT code then use
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:strip-space elements="*"/>
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:result-document href="file.text">
<xsl:apply-templates select="html/body/table/tr[1]/td[position() > 1 and position() < 6]"/>
</xsl:result-document>
</xsl:template>
<xsl:template match="td">
<xsl:param name="pos" select="position()"/>
<xsl:value-of select="., '{', ../following-sibling::tr[1]/td[$pos + 1], '}'" separator=" "/>
<xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
As for Saxon not giving you any errors, you haven't told us how you are trying to use it exactly and which version exactly.
I think, for your sample, for some reason you have moved the selection <xsl:apply-templates select="html/body/table/tr[1]/td[position() > 1 and position() < 6]"/>
I made in the context of match="/"
into a different template with a different match pattern and then added a for-each
to further change the context, it is simply that I don't expect any HTML document to contain another in a table cell, so a relative path starting with html
when your context is table cell is not likely to select anything.
If your table has more rows and you want to map each but the first to a file then I think it is better to process those rows in a separate mode that creates the result file and change the logic in the other template to pull in the function names from the first row:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:strip-space elements="*"/>
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:apply-templates select="html/body/table/tr[position() > 1]" mode="file"/>
</xsl:template>
<xsl:template match="td">
<xsl:param name="pos" select="position()"/>
<xsl:value-of select="../../tr[1]/td[$pos + 1], '{', ., '}'" separator=" "/>
<xsl:text> </xsl:text>
</xsl:template>
<xsl:template match="tr" mode="file">
<xsl:result-document href="{td[1]}.cpp">
<xsl:apply-templates select="td[position() > 1 and position() < 6]"/>
</xsl:result-document>
</xsl:template>
</xsl:stylesheet>
As for the online fiddle, sorry, but it is not set up to support xsl:result-document
as, on one hand, Saxon with security settings necessary on a public server disables that instruction, and as on the other hand the fiddle is serving as an XSLT 1 - 3 playground currently not integrating any features to create and display more than one result.
Upvotes: 1
Reputation: 349
Thanks for your answer, I use the 9th version of Saxon. To run saxon I use .bat file with the following code:
@echo off
echo "Welcome to XMLT transformation...!!!"
set /p input1="Write name of XML (with '.xml' Extension) to transform= "
echo %input1%
set /p input2="Write name of workbook-sheet (Excel Sheet name) to transform= "
echo %input2%
java -jar C:\Users\saxon9he.jar %input1% transfer_xml.xsl workbook_name=%input2%
java -jar C:\Users\saxon9he.jar %input2%.html transfer_html.xsl
pause
I firstly create an html file from xml and then on base of this html file a should create 2 text file with code.
I have already tried your code it works, thanks a lot. Could you please explain me how can I get 2 files with names at /tr/td[1]
?
Upvotes: 0