RDay
RDay

Reputation: 23

Accessing a node within a template called from within a for-each

I'm brand new to XSLT so I'm sure this is really simple, but I can't get it. I am trying to transform a report outputed into simple xml into a pipe delimited file. I can't figure out how to access wd:SSN from inside a template that is called from within a for-each. The xml output from a report looks something like this.

<wd:Report_Data xmlns:wd="urn:com.workday.report/Report_ABC">
  <wd:Report_Entry>
    <wd:Company>
      <wd:Company_Code>123</wd:Company_Code>
    </wd:Company>
    <wd:Employee_Last_Name>Smith</wd:Employee_Last_Name>
    <wd:Employee_First_Name>Joe</wd:Employee_First_Name>
    <wd:SSN>123456789</wd:SSN>
    <wd:Street_Address>123 First St</wd:Street_Address>
    <wd:City>Colorado Springs</wd:City>
    <wd:State_Province>CO</wd:State_Province>   
    <wd:ZIP_Code>80927</wd:ZIP_Code>
  </wd:Report_Entry>
  <wd:Report_Entry>
    <wd:Company>
      <wd:Company_Code>123</wd:Company_Code>
    </wd:Company>
    <wd:Employee_Last_Name>Smith</wd:Employee_Last_Name>
    <wd:Employee_First_Name>Sally</wd:Employee_First_Name>
    <wd:SSN>123456790</wd:SSN>
    <wd:Street_Address>123 First St</wd:Street_Address>
    <wd:City>Colorado Springs</wd:City>
    <wd:State_Province>CO</wd:State_Province>
    <wd:ZIP_Code>80927</wd:ZIP_Code>
  </wd:Report_Entry>

Then my code looks like this

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:strip-space elements="*"/>
<xsl:output method="text" indent="no"/>
<xsl:template match="wd:Report_Data" xmlns:wd="urn:com.workday.report/Report_ABC">

  <!-- Loop thru employee records for Company 123 -->
  <xsl:for-each select="wd:Report_Entry[wd:Company/wd:Company_Code = '123']">
    <xsl:call-template name="ProcessCompanyEmployee"/>      
  </xsl:for-each>
</xsl:template>

<!-- Process Company Employee -->
<xsl:template name="ProcessCompanyEmployee">
<!-- EMP Employee Record -->
  <xsl:text>EMP|N|N</xsl:text>
  <xsl:text>|</xsl:text>
  <xsl:text>|</xsl:text>
  <xsl:value-of select="wd:SSN"/>
  <xsl:text>||</xsl:text>
  <xsl:call-template name="insertNewLine"/>
</xsl:template>

Thanks for your help!

Upvotes: 2

Views: 328

Answers (2)

Daniel Haley
Daniel Haley

Reputation: 52878

You're binding the namespace on one xsl:template, but also trying to use it in another xsl:template.

Try moving your xmlns:wd declaration up to the xsl:stylesheet.

Example...

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:wd="urn:com.workday.report/Report_ABC">
  <xsl:strip-space elements="*"/>
  <xsl:output method="text" indent="no"/>

  <xsl:template match="wd:Report_Data">
    <!-- Loop thru employee records for Company 123 -->
    <xsl:for-each select="wd:Report_Entry[wd:Company/wd:Company_Code = '123']">
      <xsl:call-template name="ProcessCompanyEmployee"/>      
    </xsl:for-each>
  </xsl:template>

  <!-- Process Company Employee -->
  <xsl:template name="ProcessCompanyEmployee">
    <!-- EMP Employee Record -->
    <xsl:text>EMP|N|N</xsl:text>
    <xsl:text>|</xsl:text>
    <xsl:text>|</xsl:text>
    <xsl:value-of select="wd:SSN"/>
    <xsl:text>||</xsl:text>
    <xsl:call-template name="insertNewLine"/>
  </xsl:template>

  <xsl:template name="insertNewLine">
    <xsl:text>&#xA;</xsl:text>
  </xsl:template>
</xsl:stylesheet>

Also, since you're using XSLT 2.0, you could not use a prefix at all in your XPath's and add:

xpath-default-namespace="urn:com.workday.report/Report_ABC"

to xsl:stylesheet.

Example...

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xpath-default-namespace="urn:com.workday.report/Report_ABC">
  <xsl:strip-space elements="*"/>
  <xsl:output method="text" indent="no"/>

  <xsl:template match="Report_Data">
    <!-- Loop thru employee records for Company 123 -->
    <xsl:for-each select="Report_Entry[Company/Company_Code = '123']">
      <xsl:call-template name="ProcessCompanyEmployee"/>      
    </xsl:for-each>
  </xsl:template>

  <!-- Process Company Employee -->
  <xsl:template name="ProcessCompanyEmployee">
    <!-- EMP Employee Record -->
    <xsl:text>EMP|N|N</xsl:text>
    <xsl:text>|</xsl:text>
    <xsl:text>|</xsl:text>
    <xsl:value-of select="SSN"/>
    <xsl:text>||</xsl:text>
    <xsl:call-template name="insertNewLine"/>
  </xsl:template>

  <xsl:template name="insertNewLine">
    <xsl:text>&#xA;</xsl:text>
  </xsl:template>
</xsl:stylesheet>

Upvotes: 1

Geoff
Geoff

Reputation: 568

In your for-each select you've got [wd:Company/wd:Company_Code = '123'], but the XML doesn't contain a wd:Company element.

The following template works to transform your XML:

<xsl:template match="/">
    <xsl:for-each select="//wd:Report_Entry[wd:Company_Code = '123']">
        <xsl:text>EMP|N|N</xsl:text>
        ...
        <xsl:value-of select="wd:SSN"/>
        ...
    </xsl:for-each>
</xsl:template>

Using your original matches/selects as follows also works:

<xsl:template match="wd:Report_Data">
    <xsl:for-each select="wd:Report_Entry[wd:Company_Code = '123']">

When testing XSLT it helps to reduce use of templates and get it operating to select one element (say SSN), then build back up from there.

Upvotes: 0

Related Questions