Skip to content

Instantly share code, notes, and snippets.

@r4hulp
Last active July 14, 2026 19:49
Show Gist options
  • Select an option

  • Save r4hulp/94f1e59140506449d8e0b386b40c79f3 to your computer and use it in GitHub Desktop.

Select an option

Save r4hulp/94f1e59140506449d8e0b386b40c79f3 to your computer and use it in GitHub Desktop.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:wd="urn:com.workday.report/CR_VS_NEW_HIRES"
xmlns:xtt="urn:com.workday/xtt"
exclude-result-prefixes="wd">
<!--
The XSLT produces valid XML first.
Workday XTT then converts it into CSV.
-->
<xsl:output
method="xml"
encoding="UTF-8"
omit-xml-declaration="no"
indent="yes"/>
<xsl:template match="/">
<!--
Newline between:
- header
- worker row 1
- worker row 2
etc.
-->
<File xtt:separator="&#x0D;&#x0A;">
<!-- CSV header -->
<Header xtt:separator=",">
<Employee_ID>Employee_ID</Employee_ID>
<Legal_First_Name>Legal_First_Name</Legal_First_Name>
<Legal_Last_Name>Legal_Last_Name</Legal_Last_Name>
<Location_Country>Location_Country</Location_Country>
<Language>Language</Language>
<Work_Email>Work_Email</Work_Email>
<Home_Email>Home_Email</Home_Email>
<Job_Profile>Job_Profile</Job_Profile>
<Hire_Date>Hire_Date</Hire_Date>
<Termination_Date>Termination_Date</Termination_Date>
<Active>Active</Active>
<Worker_Type>Worker_Type</Worker_Type>
</Header>
<!-- Process every custom-report row -->
<xsl:for-each select="wd:Report_Data/wd:Report_Entry">
<xsl:variable name="country"
select="normalize-space(
wd:Employee_s_Country_ISO_Code
)"/>
<xsl:variable name="hireDate"
select="normalize-space(wd:Hire_Date)"/>
<!-- Exact alias from your report: lowercase t -->
<xsl:variable name="terminationDate"
select="normalize-space(wd:termination_date)"/>
<Record xtt:separator=",">
<!-- Employee ID -->
<Employee_ID>
<xsl:call-template name="csv-value">
<xsl:with-param
name="value"
select="normalize-space(wd:Employee_ID)"/>
</xsl:call-template>
</Employee_ID>
<!-- Legal first name -->
<Legal_First_Name>
<xsl:call-template name="csv-value">
<xsl:with-param
name="value"
select="normalize-space(
wd:Legal_First_Name
)"/>
</xsl:call-template>
</Legal_First_Name>
<!-- Legal last name -->
<Legal_Last_Name>
<xsl:call-template name="csv-value">
<xsl:with-param
name="value"
select="normalize-space(
wd:Legal_Last_Name
)"/>
</xsl:call-template>
</Legal_Last_Name>
<!-- Country: print exactly as received -->
<Location_Country>
<xsl:call-template name="csv-value">
<xsl:with-param
name="value"
select="$country"/>
</xsl:call-template>
</Location_Country>
<!--
Required language mapping:
US -> ENG
NL -> DUT
DE -> GER
FR -> FRE
anything else -> NA
We deliberately ignore wd:Language because that
contains the worker's actual language, not the
assignment's country-based output value.
-->
<Language>
<xsl:call-template name="csv-value">
<xsl:with-param name="value">
<xsl:choose>
<xsl:when test="$country = 'US'">
<xsl:text>ENG</xsl:text>
</xsl:when>
<xsl:when test="$country = 'NL'">
<xsl:text>DUT</xsl:text>
</xsl:when>
<xsl:when test="$country = 'DE'">
<xsl:text>GER</xsl:text>
</xsl:when>
<xsl:when test="$country = 'FR'">
<xsl:text>FRE</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>NA</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:with-param>
</xsl:call-template>
</Language>
<!-- Work email comes from Descriptor attribute -->
<Work_Email>
<xsl:call-template name="csv-value">
<xsl:with-param
name="value"
select="normalize-space(
wd:Email_-_Work/@wd:Descriptor
)"/>
</xsl:call-template>
</Work_Email>
<!-- Home email comes from Descriptor attribute -->
<Home_Email>
<xsl:call-template name="csv-value">
<xsl:with-param
name="value"
select="normalize-space(
wd:Email_-_Home/@wd:Descriptor
)"/>
</xsl:call-template>
</Home_Email>
<!-- Job profile display value -->
<Job_Profile>
<xsl:call-template name="csv-value">
<xsl:with-param
name="value"
select="normalize-space(
wd:Job_Profile/@wd:Descriptor
)"/>
</xsl:call-template>
</Job_Profile>
<!-- Hire date as DDMMYYYY -->
<Hire_Date>
<xsl:call-template name="csv-value">
<xsl:with-param name="value">
<xsl:call-template name="format-date">
<xsl:with-param
name="date"
select="$hireDate"/>
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</Hire_Date>
<!--
Termination date as DDMMYYYY.
Missing element produces an empty CSV field.
-->
<Termination_Date>
<xsl:call-template name="csv-value">
<xsl:with-param name="value">
<xsl:call-template name="format-date">
<xsl:with-param
name="date"
select="$terminationDate"/>
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</Termination_Date>
<!-- Convert report's Active text to Boolean -->
<Active>
<xsl:choose>
<xsl:when test="
normalize-space(wd:Active) = 'Active'
">
<xsl:text>true</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>false</xsl:text>
</xsl:otherwise>
</xsl:choose>
</Active>
<!-- Worker type printed exactly as received -->
<Worker_Type>
<xsl:call-template name="csv-value">
<xsl:with-param
name="value"
select="normalize-space(
wd:Worker_Type/@wd:Descriptor
)"/>
</xsl:call-template>
</Worker_Type>
</Record>
</xsl:for-each>
</File>
</xsl:template>
<!--
Handles dates such as:
2022-02-01-08:00
2022-02-01
Both become:
01022022
-->
<xsl:template name="format-date">
<xsl:param name="date"/>
<xsl:choose>
<xsl:when test="
string-length(normalize-space($date)) &gt;= 10
and substring($date, 5, 1) = '-'
and substring($date, 8, 1) = '-'
">
<xsl:value-of select="substring($date, 9, 2)"/>
<xsl:value-of select="substring($date, 6, 2)"/>
<xsl:value-of select="substring($date, 1, 4)"/>
</xsl:when>
<!-- Missing or unexpected date -->
<xsl:otherwise/>
</xsl:choose>
</xsl:template>
<!--
Wrap every text value in quotation marks.
A missing source field becomes "".
-->
<xsl:template name="csv-value">
<xsl:param name="value"/>
<xsl:text>"</xsl:text>
<xsl:call-template name="escape-quotes">
<xsl:with-param
name="value"
select="string($value)"/>
</xsl:call-template>
<xsl:text>"</xsl:text>
</xsl:template>
<!--
CSV escaping:
A value containing " is changed to "".
-->
<xsl:template name="escape-quotes">
<xsl:param name="value"/>
<xsl:choose>
<xsl:when test="contains($value, '&quot;')">
<xsl:value-of
select="substring-before($value, '&quot;')"/>
<xsl:text>""</xsl:text>
<xsl:call-template name="escape-quotes">
<xsl:with-param
name="value"
select="substring-after(
$value,
'&quot;'
)"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$value"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment