xsltxslt-2.0xslt-grouping

XSLT : Create a new xml/csv structure


I'd like to ask for your guidance to better achieve the desired output. I have an XSLT file that I don't have control on it and I'd like to apply a transformation that modify the initial structure.

My goal is to recreate the report_entry structure based on the years found in the all_releases structures.

XML Structure (Input)

<?xml version="1.0" encoding="UTF-8"?>
<wd:Report_Data xmlns:wd="http://www.gaming.org/">
  <wd:Report_Entry>
    <wd:id>150</wd:id>
    <wd:name>Call-of-Duty</wd:name>
    <wd:all_releases>
        <wd:year>2017</wd:year>
    </wd:all_releases>
    <wd:all_releases>
        <wd:year>2020</wd:year>
    </wd:all_releases>
  </wd:Report_Entry>
  <wd:Report_Entry>
    <wd:id>250</wd:id>
    <wd:name>Metal Slug</wd:name>
    <wd:all_releases>
        <wd:year>2003</wd:year>
    </wd:all_releases>
  </wd:Report_Entry>
</wd:Report_Data>

Expected XML strucutre (Input)

<?xml version="1.0" encoding="UTF-8"?>
<wd:Report_Data xmlns:wd="http://www.gaming.org/">
  <wd:Report_Entry>
    <wd:id>150</wd:id>
    <wd:name>Call-of-Duty</wd:name>
    <wd:year>2017</wd:year>
  </wd:Report_Entry>
  <wd:Report_Entry>
    <wd:id>150</wd:id>
    <wd:name>Call-of-Duty</wd:name>
    <wd:year>2020</wd:year>
  </wd:Report_Entry>
  <wd:Report_Entry>
    <wd:id>250</wd:id>
    <wd:name>Metal Slug</wd:name>
    <wd:year>2003</wd:year>
  </wd:Report_Entry>
</wd:Report_Data>

My XSLT

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:wd="http://www.gaming.org/" >
<xsl:output method="text" byte-order-mark="yes" indent="no" encoding="utf-8"/>

    <xsl:template match="/">
        <File>
         <xsl:call-template name="Header"/>
         <xsl:text>&#xa;</xsl:text>
         <xsl:for-each select="/wd:Report_Data/wd:Report_Entry"> 
            <xsl:call-template name="Rows"/>
        </xsl:for-each> 
        </File>
    </xsl:template>

    <xsl:template name="Header">
        <xsl:text>"id";</xsl:text>
        <xsl:text>"name";</xsl:text>
        <xsl:text>"year";</xsl:text>
    </xsl:template>

    <xsl:template name="Rows">
        <col>"<xsl:value-of select="wd:id"/>";</col>
        <col>"<xsl:value-of select="wd:name"/>";</col>
        <col>"<xsl:value-of select="wd:all_releases/wd:year"/>";</col>
    </xsl:template>
</xsl:stylesheet>

Current output

<File xmlns:wd="http://www.gaming.org/">"id";"name";"year";
   <col>"1000";</col>
   <col>"Call-of-Duty";</col>
   <col>"2017 2020";</col>
   <col>"2000";</col>
   <col>"Metal Slug";</col>
   <col>"2003";</col>
</File>

Expected output

<File xmlns:wd="http://www.gaming.org/">"id";"name";"year";
   <col>"150";</col>
   <col>"Call-of-Duty";</col>
   <col>"2017";</col>
   <col>"150";</col>
   <col>"Call-of-Duty";</col>
   <col>"2020";</col>
   <col>"250";</col>
   <col>"Metal Slug";</col>
   <col>"2003";</col>
</File>

Solution

  • I don't fully understand your output format. It's clearly XML, but your existing stylesheet specifies text as the output method, which makes no sense to me.

    I think something like this should produce the result you want or at least close to it:

    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:wd="http://www.gaming.org/">
    <xsl:output method="xml" indent="yes"/>
    
    <xsl:template match="/wd:Report_Data ">
        <File>
            <xsl:text>"id";"name";"year";&#10;</xsl:text>
            <xsl:for-each select="wd:Report_Entry">
                <xsl:variable name="idname">
                    <col>"<xsl:value-of select="wd:id"/>";</col>
                    <col>"<xsl:value-of select="wd:name"/>";</col>
                </xsl:variable>
                <xsl:for-each select="wd:all_releases">
                    <xsl:copy-of select="$idname"/>
                    <col>"<xsl:value-of select="wd:year"/>";</col>
                </xsl:for-each>
            </xsl:for-each>
        </File>
    </xsl:template>
    
    </xsl:stylesheet>
    

    You may also want to add exclude-result-prefixes="wd" to the stylesheet element to get rid of the redundant namespace declaration.