2

I have a source XML file that I want to convert into another XML file with a different format. My source XML file uses attributes (I think, correct me if I'm wrong here) and the target XML format should be plain parent-child XML tags. I have no issues with a straight forward approach.

However, I need to find a way to concatenate 2 or more fields into a single element using XSLT. I tried using variables then concatenating them however, I am having some issues with variables and they can only be assigned once.

My XML is like this:

<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="http://www.taleo.com/ws/integration/toolkit/2005/07" xmlns:ns1="http://www.taleo.com/ws/integration/toolkit/2005/07" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Attributes><Attribute name="count">1</Attribute><Attribute name="duration">0:00:00.109</Attribute><Attribute name="entity">SourcingRequest</Attribute><Attribute name="mode">XML</Attribute><Attribute name="version">http://www.taleo.com/ws/tee800/2009/01</Attribute></Attributes><Content>
<ExportXML xmlns="http://www.taleo.com/ws/integration/toolkit/2005/07">
    <record>
        <field name="Title">Project Analyst</field>
        <field name="Position_ID">64057</field>
        <field name="RequisitionNumber">180767</field>
        <field name="LocationCode">HQ</field>
        <field name="LocationName">Headquarters</field>
        <field name="LocationCountry">Country</field>
        <field name="LocationCity">City</field>
    </record>
</ExportXML></Content></Document>

Then my XSL is like this:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" xmlns:itk="http://www.taleo.com/ws/integration/toolkit/2005/07">
  <xsl:output method="xml" encoding="UTF-8" omit-xml-declaration="yes" cdata-section-elements="DescriptionInternal DescriptionExternal QualificationExternal QualificationInternal"/>
  <xsl:template match="text()"/>
  <xsl:template match="itk:record">
    <xsl:element name="Job">
        <xsl:for-each select="itk:field">
            <!-- Set variables -->
            <xsl:variable name="location_code">
              <xsl:if test="@name='LocationCode'">
                <xsl:value-of select="." />
              </xsl:if>
            </xsl:variable>
            <xsl:variable name="location_name">
              <xsl:if test="@name='LocationName'">
                <xsl:value-of select="." />
              </xsl:if>
            </xsl:variable>
            <xsl:variable name="location_country">
              <xsl:if test="@name='LocationCountry'">
                <xsl:value-of select="." />
              </xsl:if>
            </xsl:variable>
            <xsl:variable name="location_city">
              <xsl:if test="@name='LocationCity'">
                <xsl:value-of select="." />
              </xsl:if>
            </xsl:variable>
            <xsl:choose>
              <xsl:when test="@name='LocationCode' or @name='LocationName' or @name='LocationCountry' or @name='LocationCity'">
                <xsl:if test="@name='LocationCity'">
                  <xsl:element name="Location">
                    <xsl:value-of select="concat($location_code,$location_name,$location_country,$location_city)" />
                  </xsl:element>
                  <xsl:element name="LocationCode">
                    <xsl:value-of select="$location_code" />
                  </xsl:element>
                  <xsl:element name="LocationName">
                    <xsl:value-of select="$location_code" />
                  </xsl:element>
                </xsl:if>
              </xsl:when>
              <xsl:otherwise>
                <!-- Set variables. -->
                <xsl:variable name="NodeName" select="@name"/>
                <xsl:element name="{@name}">                
                    <xsl:value-of select="."/>
                </xsl:element>                
              </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each>             
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

However, my output is like this:

<Job>
   <Title>Project Analyst</Title>
   <Position_ID>64057</Position_ID>
   <RequisitionNumber>180767</RequisitionNumber>
   <Location>City</Location>
</Job>

But my desired output should be like this:

<Job>
   <Title>Project Analyst</Title>
   <Position_ID>64057</Position_ID>
   <RequisitionNumber>180767</RequisitionNumber>
   <Location>HQ Headquarters Country City</Location>
</Job>    

If my guess is right, I think the loop resets the values of variables. So whatever was last will be the value.

Is there any other way I can achieve the desired output. My options are limited to XSL although my source file can be changed into CSV format.

Appreciate any help.

1 Answer 1

1

Is there a reason why you can't do simply:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:itk="http://www.taleo.com/ws/integration/toolkit/2005/07" 
exclude-result-prefixes="itk">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/itk:Document">
    <xsl:apply-templates select="itk:Content/itk:ExportXML/itk:record"/>
</xsl:template>

<xsl:template match="itk:record">
    <Job>
        <Title>
            <xsl:value-of select="itk:field[@name='Title']" />
        </Title>
        <Position_ID>
            <xsl:value-of select="itk:field[@name='Position_ID']" />
        </Position_ID>
        <RequisitionNumber>
            <xsl:value-of select="itk:field[@name='RequisitionNumber']" />
        </RequisitionNumber>
        <Location>
            <xsl:value-of select="itk:field[@name='LocationCode']" />
            <xsl:text> </xsl:text>
            <xsl:value-of select="itk:field[@name='LocationName']" />
            <xsl:text> </xsl:text>
            <xsl:value-of select="itk:field[@name='LocationCountry']" />
            <xsl:text> </xsl:text>
            <xsl:value-of select="itk:field[@name='LocationCity']" />
        </Location>
    </Job>    
</xsl:template>

</xsl:stylesheet>

Or, if using XSLT 2.0, even simpler:

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xpath-default-namespace="http://www.taleo.com/ws/integration/toolkit/2005/07" >
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/Document">
    <xsl:apply-templates select="Content/ExportXML/record"/>
</xsl:template>

<xsl:template match="record">
    <Job>
        <xsl:for-each select="field[not(starts-with(@name, 'Location'))]">
            <xsl:element name="{@name}">
                <xsl:value-of select="." />
            </xsl:element>
        </xsl:for-each>
        <Location>
            <xsl:value-of select="field[starts-with(@name, 'Location')]" />
        </Location>
    </Job>    
</xsl:template>

</xsl:stylesheet>
Sign up to request clarification or add additional context in comments.

3 Comments

I actually did get it to work I guess somewaht similar to this solution. I posted an answer a few minutes after this so marking this as the answer.
I may have missed something, but I don't see anything here that depends on XSLT 2.0.
@MichaelKay The last xsl:value-of retrieves 4 values with a separator. In XSLT 1.0 it would have returned only the value of LocationCode. In addition, there is no xpath-default-namespace in XSLT 1.0.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.