Skip to content

Instantly share code, notes, and snippets.

@r4hulp
Created July 13, 2026 10:26
Show Gist options
  • Select an option

  • Save r4hulp/9b41c01cd4a5a321326261a1b9b3b1da to your computer and use it in GitHub Desktop.

Select an option

Save r4hulp/9b41c01cd4a5a321326261a1b9b3b1da 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:ws="urn:com.workday/workersync"
xmlns:xtt="urn:com.workday/xtt"
exclude-result-prefixes="ws">
<!--
Important:
The XSLT must first output valid XML.
Workday XTT then converts that XML into CSV text.
-->
<xsl:output method="xml"
encoding="UTF-8"
omit-xml-declaration="no"
indent="yes"/>
<xsl:template match="/">
<File>
<!-- =================================================
CSV header
XTT places commas between the child elements.
================================================= -->
<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>
<!-- =================================================
One Record element becomes one CSV row.
================================================= -->
<xsl:for-each select="ws:Worker_Sync/ws:Worker">
<Record xtt:separator=",">
<!-- Employee ID -->
<Employee_ID>
<xsl:call-template name="csv-value">
<xsl:with-param name="value"
select="normalize-space(ws:Summary/ws: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(ws:Personal/ws:Name_Data/ws: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(ws:Personal/ws:Name_Data/ws:Last_Name)"/>
</xsl:call-template>
</Legal_Last_Name>
<!-- Country printed exactly as received -->
<Location_Country>
<xsl:call-template name="csv-value">
<xsl:with-param name="value"
select="normalize-space(ws:Personal/ws:Address_Data/ws:Country)"/>
</xsl:call-template>
</Location_Country>
<!-- Language derived from country -->
<Language>
<xsl:variable name="country"
select="normalize-space(ws:Personal/ws:Address_Data/ws:Country)"/>
<xsl:call-template name="csv-value">
<xsl:with-param name="value">
<xsl:choose>
<xsl:when test="$country = 'US'">ENG</xsl:when>
<xsl:when test="$country = 'NL'">DUT</xsl:when>
<xsl:when test="$country = 'DE'">GER</xsl:when>
<xsl:when test="$country = 'FR'">FRE</xsl:when>
<xsl:otherwise>NA</xsl:otherwise>
</xsl:choose>
</xsl:with-param>
</xsl:call-template>
</Language>
<!-- Work email -->
<Work_Email>
<xsl:call-template name="csv-value">
<xsl:with-param name="value"
select="normalize-space(ws:Personal/ws:Email_Data/ws:Email_Address)"/>
</xsl:call-template>
</Work_Email>
<!--
Current XML does not contain a separate
home email node, so it remains blank.
-->
<Home_Email>
<xsl:call-template name="csv-value">
<xsl:with-param name="value" select="''"/>
</xsl:call-template>
</Home_Email>
<!-- Job profile -->
<Job_Profile>
<xsl:call-template name="csv-value">
<xsl:with-param name="value"
select="normalize-space(ws:Position/ws:Job_Profile)"/>
</xsl:call-template>
</Job_Profile>
<!-- Hire date: YYYY-MM-DD to DDMMYYYY -->
<Hire_Date>
<xsl:variable name="hireDate"
select="normalize-space(ws:Status/ws: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 -->
<Termination_Date>
<xsl:variable name="terminationDate"
select="normalize-space(ws:Status/ws: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>
<!--
Active:
no termination date = true
termination date present = false
-->
<Active>
<xsl:choose>
<xsl:when test="
normalize-space(
ws:Status/ws:Termination_Date
) = ''
">
<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(ws:Position/ws:Worker_Type)"/>
</xsl:call-template>
</Worker_Type>
</Record>
</xsl:for-each>
</File>
</xsl:template>
<!-- =========================================================
Convert YYYY-MM-DD to DDMMYYYY.
Missing or malformed dates return blank.
========================================================= -->
<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>
<xsl:otherwise/>
</xsl:choose>
</xsl:template>
<!-- =========================================================
Wrap text fields in quotation marks.
Missing values become "".
Embedded quotes are doubled for CSV.
========================================================= -->
<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>
<!-- Convert " to "" inside CSV values -->
<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