2

I am trying to use a XSLT 2.0 transformation to split a XML file into smaller files based on groups of items. To execute the transformation I am using a camel route. My problem is that when the xslt transformation is run the resulting files are saved "outside" the route.

So, for example, given the following camel route:

from("{{input.endpoint}}")
.to("xslt:xslts/ics/MappingMapTostudents.xslt?saxon=true")
.to("{{output.endpoint}}");

I would be expecting the resulting xml files to be created in the {output.endpoint} folder. Unfortunately saxon is saving the files in the root folder where the executable (camel app) is. How can I have the files saved to {{output.endpoint}} or better, passed on to the following endpoint?

Following an XML example:

<?xml version="1.0" encoding="UTF-8"?>
<class> 
    <students>
        <student>
            <firstname>Albert</firstname> 
            <group>A</group>
        </student> 
        <student> 
            <firstname>Isaac</firstname> 
            <group>A</group>
        </student> 
        <student> 
            <firstname>Leonardo</firstname> 
            <group>B</group>
        </student> 
        <student>
            <firstname>Enrico</firstname> 
            <group>B</group>
        </student> 
        <student> 
            <firstname>Marie</firstname> 
            <group>C</group>
        </student> 
        <student> 
            <firstname>Rosalind</firstname> 
            <group>C</group>
        </student>
        <student> 
            <firstname>Ada</firstname> 
            <group>D</group>
        </student>
    </students>
</class>

The XSLT transformation:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:grp="http://www.altova.com/Mapforce/grouping" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="grp xs fn">
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    <xsl:function name="grp:var2_function">
        <xsl:param name="var1_param" as="node()"/>
        <xsl:for-each select="$var1_param/student">
            <xsl:sequence select="fn:string(group)"/>
        </xsl:for-each>
    </xsl:function>
    <xsl:template match="/">
        <xsl:for-each-group select="class/students" group-by="grp:var2_function(.)">
            <xsl:variable name="var3_resultof_grouping_key" as="xs:string" select="current-grouping-key()"/>
            <xsl:result-document href="{fn:concat($var3_resultof_grouping_key, '.xml ')}" encoding="UTF-8">
                <class>
                    <xsl:for-each select="(current-group()/student)[(fn:string(group) = $var3_resultof_grouping_key)]">
                        <students>
                            <student>
                                <firstname>
                                    <xsl:sequence select="fn:string(firstname)"/>
                                </firstname>
                                <group>
                                    <xsl:sequence select="$var3_resultof_grouping_key"/>
                                </group>
                            </student>
                        </students>
                    </xsl:for-each>
                </class>
            </xsl:result-document>
        </xsl:for-each-group>
    </xsl:template>
</xsl:stylesheet>
aldebaran-ms
  • 666
  • 6
  • 18
  • 3
    I don't know about the integration of Saxon with Apache Camel which I think is the key to getting the files in the desired location, but as for your stylesheet, the whole code is rather convoluted, you could reduce the grouping to ``. – Martin Honnen Mar 14 '19 at 18:56
  • Hi Martin, thanks. The xslt file is generated with altova MapForce and it's just a proof of concept. My real xslt is far more complicated. – aldebaran-ms Mar 15 '19 at 09:17

2 Answers2

1

I know very little about Apache-Camel, and unfortunately questions about the technology on StackOverflow don't seem to have a very high success rate.

The documentation at http://camel.apache.org/xslt.html gives no clue about how to set the base output URI, which is used by Saxon for resolving any relative URI appearing in xsl:result-document/@href.

The simplest approach that comes to mind is to pass a parameter to the transformation, whose value is the absolute path to the output directory:

<xsl:param name="outDir" as="xs:string"/>
...
<xsl:result-document 
   href="file:///{$outDir}{$var3_resultof_grouping_key}.xml"/>

But someone who knows Apache Camel might be able to suggest a more elegant solution.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
  • Thanks Michael. That's what I have already done as a workaround but it's an ugly solution because it breaks my camel route and force me to split it in two segments. – aldebaran-ms Mar 15 '19 at 09:14
1

You may try to force an output of type "file".

to("xslt:xslts/ics/MappingMapTostudents.xslt?saxon=true&output=file")

Then, as the doc explains it, you have to fill a Camel header with the wanted target file path:

For file you must specify the filename in the IN header with the key Exchange.XSLT_FILE_NAME which is also CamelXsltFileName. Also any paths leading to the filename must be created beforehand, otherwise an exception is thrown at runtime.

Good luck

TacheDeChoco
  • 3,683
  • 1
  • 14
  • 17