niki b
niki b

Reputation: 989

XSLT Apply Templates same name different nodes

How can you apply different templates to different sub nodes that have the same name?

I am given an xml that I cannot change.

To oversimplify with an example (the real xml is much more complicated than this), I want to apply different templates to Employees and Managers, but their subnodes are both "Employees". The xslt below will not work because there are 2 Employee templates.

FYI, I'm a newbie with xslts so I apologize if this turns out to be very easy to solve.

Thanks in advance! Any help will be appreciated.

XML

<Company>
    <CompanyId>1</CompanyId>
    <CompanyName>Company B</CompanyName>
    <Employees>
        <Employee>
            <EmployeeId>1</EmployeeId>
            <FirstName>Jane</FirstName>
            <LastName>Doe</LastName>
        </Employee>
        <Employee>
            <EmployeeId>2</EmployeeId>
            <FirstName>James</FirstName>
            <LastName>Smith</LastName>
        </Employee>
    </Employees>
    <Managers>
        <Employee>
            <EmployeeId>3</EmployeeId>
            <FirstName>Michael</FirstName>
            <LastName>Johnson</LastName>
            <DepartmentName>Sales</DepartmentName>
            <NumberOfStaff>20</NumberOfStaff>
        </Employee>
        <Employee>
            <EmployeeId>2</EmployeeId>
            <FirstName>James</FirstName>
            <LastName>Smith</LastName>
            <DepartmentName>IT</DepartmentName>
            <NumberOfStaff>50</NumberOfStaff>
        </Employee>
    </Managers>
</Company>

XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:ms="urn:schemas-microsoft-com:xslt"
                xmlns:dt="urn:schemas-microsoft-com:datatypes">

  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="/Company"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Company">
    COMPANY INFO<br />
    Company Id: <xsl:value-of select="CompanyId" /><br />
    Company Name: <xsl:value-of select="CompanyName" /><br /> 

    <br />
    EMPLOYEES<br />
    <xsl:apply-templates select="/Company/Employees/Employee"/>

    <br />
    MANAGERS<br />  
    <xsl:apply-templates select="/Company/Managers/Employee"/>

    <br />
  </xsl:template>

  <xsl:template match="Employee">
    <br />
    Employee Id: <xsl:value-of select="EmployeeId" /><br />
    Employee Name:  <xsl:value-of select="LastName" />,<xsl:value-of select="FirstName" /><br /> 
  </xsl:template>

  <xsl:template match="Employee">
    <br />
    Manager Id: <xsl:value-of select="EmployeeId" /><br />
    Manager Name:  <xsl:value-of select="LastName" />,<xsl:value-of select="FirstName" /><br /> 
    Department Name: <xsl:value-of select="DepartmentName" /><br /> 
    Number of Staff: <xsl:value-of select="NumberOfStaff" /><br /> 
  </xsl:template>

</xsl:stylesheet>

DESIRED OUTPUT

 COMPANY INFO
 Company Id: 1
 Company Name: Company B

 EMPLOYEES

 Employee Id: 1
 Employee Name: Doe,Jane

 Employee Id: 2
 Employee Name: Smith,James

 MANAGERS

 Manager Id: 3
 Manager Name: Johnson,Michael
 Department Name: Sales
 Number of Staff: 20

 Manager Id: 2
 Manager Name: Smith,James
 Department Name: IT
 Number of Staff: 50

Upvotes: 1

Views: 1609

Answers (1)

Tim C
Tim C

Reputation: 70598

You can specify the parent in the match attribute on the template

For Managers...

<xsl:template match="Managers/Employee">

For Employees...

<xsl:template match="Employees/Employee">

Note that, although not necessarily in this instance, another option would be to make us of "modes"

<xsl:apply-templates select="/Company/Employees/Employee" mode="Employees" />

<xsl:apply-templates select="/Company/Managers/Employee" mode="Managers" />

Then you could write your template matches like this:

<xsl:template match="Employee" mode="Employees">

<xsl:template match="Employee" mode="Managers">

Upvotes: 6

Related Questions