XSLT - how to group output by common child element value

Viewed 48

I have an XML file like the below where I may have multiple records with a common child element like so:

<content xmlns="http://www.taleo.com/ws/integration/toolkit/2005/07">
<ExportXML>
    <record>
        <job_id>19013280</job_id>
        <title>Senior Services /  Platform Engineer - LoungeBuddy</title>
        <coll>abc</coll>
    </record>
    <record>
        <job_id>19013280</job_id>
        <title>Senior Services /  Platform Engineer - LoungeBuddy</title>
        <coll>xyz</coll>    
    </record>
</ExportXML>
</content>

How would I transform this to the below using XSLT 2.0?

<EF_Position>
   <job_id>19013280</job_id>
   <title>Senior Services /  Platform Engineer - LoungeBuddy</title>
<coll1>
<coll>abc</coll>
<coll>xyz</coll>
</coll1>
</EF_Position>

I tried with code but some how it is not working.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:to="http://www.taleo.com/ws/integration/toolkit/2005/07" xmlns:util="http://www.mavixconsulting.com/2013/XSL/transform" exclude-result-prefixes="to util">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="./ExportXML">
<xsl:for-each-group select="record" group-by="job_id">
<EF_Position>
<xsl:sequence select="job_id" />
<title>
      <xsl:value-of select="title"/>
    </title>
    <coll1>
    <xsl:for-each select="current-group()">
    <coll>
<xsl:value-of select="coll"/>
</coll>
</xsl:for-each>
</coll1>
</EF_Position>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>

The issue is because of tag <content xmlns="http://www.taleo.com/ws/integration/toolkit/2005/07">.

If I removed xmlns="http://www.taleo.com/ws/integration/toolkit/2005/07" it is working fine.

I'm fairly new to XSLT so please excuse the potentially novice question. Any guidance would be appreciated here. Thanks in advance.

1 Answers

To deal with namespaces you can declare prefixes in your xslt pointing to the URI reference of the namespace, like you did ;-) . In your case : xmlns:to="http://www.taleo.com/ws/integration/toolkit/2005/07".

But then you have to use them also like this:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:to="http://www.taleo.com/ws/integration/toolkit/2005/07" exclude-result-prefixes="#all" >
  <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
  
  <xsl:template match="to:ExportXML">
    <xsl:for-each-group select="to:record" group-by="to:job_id">
      <EF_Position>
        <job_id>
          <xsl:value-of select="to:job_id/text()"/>
        </job_id>
        <title>
          <xsl:value-of select="to:title"/>
        </title>
        <coll1>
          <xsl:for-each select="current-group()">
            <coll>
              <xsl:value-of select="to:coll"/>
            </coll>
          </xsl:for-each>
        </coll1>
      </EF_Position>
    </xsl:for-each-group>
  </xsl:template>
</xsl:stylesheet>

Or if you have a namespace that is used almost everywhere, you can declare a xpath-default-namespace-attribute and point to that URI reference of the namespace. Then all your XPath's in match and select will use this namespace, so you don't need a prefix. Then the xslt will look like this:

<?xml version="1.0" encoding="UTF-8"?>
<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" omit-xml-declaration="yes" indent="yes"/>
  
  <xsl:template match="ExportXML">
    <xsl:for-each-group select="record" group-by="job_id">
      <EF_Position>
        <job_id>
          <xsl:value-of select="job_id/text()"/>
        </job_id>
        <title>
          <xsl:value-of select="title"/>
        </title>
        <coll1>
          <xsl:for-each select="current-group()">
            <coll>
              <xsl:value-of select="coll"/>
            </coll>
          </xsl:for-each>
        </coll1>
      </EF_Position>
    </xsl:for-each-group>
  </xsl:template>
</xsl:stylesheet>
Related