Reputation: 742
I need to transform the XML and am having some issues...
Current XML:
<?xml version="1.0" encoding="utf-8"?>
<Employees>
<Employee>
<ManagerFirstName>Joe</ManagerFirstName>
<ManagerLastName>Schmoe</ManagerLastName>
</Employee>
</Employees>
Desired Output:
<?xml version="1.0" encoding="utf-8"?>
<Employees>
<Employee>
<supervisorName>Schmoe, Joe</supervisorName>
</Employee>
</Employees>
Current XSL:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" >
<xsl:template match="/">
<xsl:apply-templates select="*"/>
</xsl:template>
<xsl:template match="node()">
<xsl:copy><xsl:apply-templates select="node()"/></xsl:copy>
</xsl:template>
<xsl:template match="ManagerFirstName">
<supervisorName>
<xsl:apply-templates select="node()"/>
<xsl:value-of select="/ManagerLastName"/>
<xsl:text>, </xsl:text>
<xsl:value-of select="/ManagerFirstName"/>
</supervisorName>
</xsl:template>
</xsl:stylesheet>
This is not working and I can not figure it out. The XML it is outputting at the moment looks like this:
<?xml version="1.0" encoding="utf-8"?>
<Employees>
<Employee>
<supervisorName>Joe, </supervisorName>
<ManagerLastName>Schmoe/ManagerLastName>
</Employee>
</Employees>
I feel like I'm so close...
UPDATE How would I go about making sure that if ManagerFirstName and ManagerLastName are blank, that supervisorName does not have the comma inside of it?
UPDATE 2
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output indent="yes"/> <xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:apply-templates select="*"/>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Employee">
<tbl_EmployeeList><xsl:apply-templates select="@*|node()"/></tbl_EmployeeList>
</xsl:template>
<xsl:template match="tbl_EmployeeList">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<supervisorName>
<xsl:value-of select="(ManagerLastName,ManagerFirstName)" separator=", "/>
</supervisorName>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Upvotes: 4
Views: 9282
Reputation: 2109
All responses seem good, but I think that this approach is cleaner (Just replace your ManagerFirstName template by this one):
<xsl:template match="Employee">
<supervisorName>
<xsl:value-of select="concat(ManagerLastName,', ',ManagerFirstName)"/>
</supervisorName>
</xsl:template>
UPDATE:
If you want to make the comma appear only if both nodes exist and are not empty you can use an if with string-length for that:
<xsl:template match="Employee">
<supervisorName>
<xsl:value-of select="ManagerLastName"/>
<xsl:if test="string-length(ManagerLastName) and string-length(ManagerFirstName)">
<xsl:text> ,</xsl:text>
</xsl:if>
<xsl:value-of select="ManagerFirstName"/>
</supervisorName>
</xsl:template>
UPDATE 2: Yet a cleaner solution following xslt 2.0 approach, but which also covers the case of an empty node.
<xsl:template match="Employee">
<supervisorName>
<xsl:value-of select="(ManagerLastName[text()],ManagerFirstName[text()])" separator=", "/>
</supervisorName>
</xsl:template>
Upvotes: 1
Reputation: 52858
Since you're using XSLT 2.0 you can use the separator
attribute in xsl:value-of
...
XML Input
<Employees>
<Employee>
<ManagerFirstName>Joe</ManagerFirstName>
<ManagerLastName>Schmoe</ManagerLastName>
</Employee>
</Employees>
XSLT 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Employee">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<supervisorName>
<xsl:value-of select="(ManagerLastName,ManagerFirstName)" separator=", "/>
</supervisorName>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
XML Output
<Employees>
<Employee>
<supervisorName>Schmoe, Joe</supervisorName>
</Employee>
</Employees>
Note: If there is no ManagerLastName
or ManagerFirstName
, no separator will be output.
Upvotes: 5
Reputation: 243449
Here is a fully "push style" solution:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Employee">
<supervisorName><xsl:apply-templates/></supervisorName>
</xsl:template>
<xsl:template match="Employee/*">
<xsl:value-of select="concat(', ', .)"/>
</xsl:template>
<xsl:template match="Employee/*[1]"><xsl:apply-templates/></xsl:template>
</xsl:stylesheet>
Upvotes: 2
Reputation: 122364
You are close. In the ManagerFirstName
template you need a slightly different XPath to pull out the last name:
<xsl:template match="ManagerFirstName">
<supervisorName>
<xsl:value-of select="../ManagerLastName"/>
<xsl:text>, </xsl:text>
<xsl:apply-templates select="node()"/>
</supervisorName>
</xsl:template>
(the apply-templates
is sufficient to give you the value of the ManagerFirstName
, you don't need a specific value-of
for that). You then need a no-op template to stop it copying the last name independently
<xsl:template match="ManagerLastName" />
Also note that the usual identity template would match and apply-templates to @*|node()
rather than just node()
- it makes no difference in your example document because you're not using any attributes, but if your original XML had attributes then your version of the identity template would drop them.
Upvotes: 2
Reputation: 7662
You can do this in the following way:
<?xml version="1.0" encoding="UTF-8"?>
<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:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Employee">
<Employee>
<supervisorName><xsl:value-of select="concat(ManagerLastName, ', ', ManagerFirstName)"/></supervisorName>
</Employee>
</xsl:template>
</xsl:stylesheet>
Upvotes: 3