Home > Software engineering >  XML transformation with XSLT: Create multiple output files with file names from incremented variable
XML transformation with XSLT: Create multiple output files with file names from incremented variable

Time:05-20

I have an XML file like this:

<?xml version="1.0" encoding="UTF-8"?>
<xml>
    <letter n="1">
        <p>test 1</p>
    </letter>
    <letter n="2">
        <p>test 2</p>
    </letter>
    <letter n="3">
        <p>test 3</p>
    </letter>
    <letter n="4">
        <p>test 4</p>
    </letter>
</xml>

My current stylesheet, which is not working as expected, looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs" version="2.0">
    
    <xsl:output name="xml" method="xml" indent="yes"/>
    
    <!-- directory of new files -->
    <xsl:param name="dir">/ex/ex/ex/test</xsl:param>
    
    <!-- new file name = count existing xml files in directory and increment the value by 1 -->
    <xsl:param name="filename"
        select="count(collection('/ex/ex/ex/test?select=*.xml'))   1"/>
    
    <!-- output xml file for each letter-tag -->
    <xsl:template match="letter">
        <xsl:for-each-group select="." group-by="./@n">
            <xsl:for-each select="current-group()">
                <xsl:result-document format="xml" href="{$dir}/{$filename}.xml">
                    <xsl:copy-of select="./node()"/>
                </xsl:result-document>
            </xsl:for-each>
        </xsl:for-each-group>
    </xsl:template>
    
</xsl:stylesheet>

What I want to do: Read the XML file to be transformed, find all the letter tags and create a new XML file for each letter tag. (In this example the desired output would be 4 new XML files, the first with <p>test 1</p>, the second with <p>test 2</p> etc.) The file name should be the number of existing XML files in the output directory 1. So if I already have 10 files in my output directory, I want the new files to be named 11.xml, 12.xml etc. And this is what isn't working.

My problem is that I get the error message "cannot write more than one result document to the same URI".

What I want to know: How can I adapt my stylesheet to get my desired result, i. e. what can I do to output multiple XML files with an incremented parameter/variable as file name?

CodePudding user response:

If I read your requirements correctly, you want to do:

XSLT 2.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:param name="dir">/ex/ex/ex/test</xsl:param>
<xsl:variable name="n" select="count(collection(concat($dir, '?select=*.xml')))"/>

<xsl:template match="/xml">
    <xsl:for-each select="letter">
        <xsl:result-document href="{$dir}/{$n   position()}.xml">
            <xsl:copy-of select="p"/>
        </xsl:result-document>
    </xsl:for-each>
</xsl:template>
  
</xsl:stylesheet>
  • Related