ms_jordan
ms_jordan

Reputation: 161

Transforming XML with XSLT - Check if it is true or false then transform it to Y or N

<Employees xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <ListItems>
    <Employee>
      <EmployeeNo>123456</EmployeeNo>
      <FirstName>firstName</FirstName>
      <LastName>lastName</LastName>
      <Email>[email protected]</Email>
      <Active>true</Active>
    </Employee>
  </ListItems>
</Employees>

XSLT

<xsl:template match="Employee[count(descendant::Active[. = '']) = 1]">
   <xsl:variable name="Active">
      <!--<xsl:for-each select="Employees/ListItems/Employee">-->
      <xsl:choose>
         <xsl:when test="Active='true'">
            <Active>Y</Active>
         </xsl:when>
         <xsl:otherwise>
            <Active>N</Active>
         </xsl:otherwise>
      </xsl:choose>
      <!--</xsl:for-each>-->
   </xsl:variable>
</xsl:template>

I need to write an xslt when employee's record Active = true, I need to transform true to "Y", if not then "N". I wrote this XSLT but it not working

Currently = true What I need to have is = Y

Upvotes: 1

Views: 1188

Answers (3)

michael.hor257k
michael.hor257k

Reputation: 117165

To simplify the matter, try the following stylesheet:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

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

<xsl:template match="Active">
    <xsl:copy>
        <xsl:choose>
            <xsl:when test=".='true'">Y</xsl:when>
            <xsl:otherwise>N</xsl:otherwise>
        </xsl:choose>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

P.S. This solution proudly uses xsl:choose. xsl:choose is an integral part of the XSLT language, and there is absolutely nothing wrong with using it to its full advantage. It adds clarity to the code, while artificial attempts to avoid using it only end up obfuscating the code unnecessarily.

Upvotes: 1

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243599

This short and simple transformation (only two templates, no explicit conditional instructions, no repeated <xsl:copy>, no <xsl:choose>, <xsl:when> or <xsl:otherwise>):

<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="Employee/Active/text()">
     <xsl:value-of select="substring('YN', 2 - (.= 'true'), 1)"/>
  </xsl:template>

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

When applied on the following source XML document:

<Employees>
    <ListItems>
        <Employee>
            <EmployeeNo>123456</EmployeeNo>
            <FirstName>firstName</FirstName>
            <LastName>lastName</LastName>
            <Email>[email protected]</Email>
            <Active>true</Active>
        </Employee>
        <Employee>
            <EmployeeNo>234567</EmployeeNo>
            <FirstName>firstName2</FirstName>
            <LastName>lastName2</LastName>
            <Email>[email protected]</Email>
            <Active>not-quite-true</Active>
        </Employee>
    </ListItems>
</Employees>

produces the wanted, correct result:

<Employees>
   <ListItems>
      <Employee>
         <EmployeeNo>123456</EmployeeNo>
         <FirstName>firstName</FirstName>
         <LastName>lastName</LastName>
         <Email>[email protected]</Email>
         <Active>Y</Active>
      </Employee>
      <Employee>
         <EmployeeNo>234567</EmployeeNo>
         <FirstName>firstName2</FirstName>
         <LastName>lastName2</LastName>
         <Email>[email protected]</Email>
         <Active>N</Active>
      </Employee>
   </ListItems>
</Employees>

Explanation:

  1. The identity rule, unless overriden, copies every node to the output "as-is"
  2. There is just one other template, and it overrides the identity rule for any text-node that is a child of an Active element that is a child of an Employee element
  3. The latter template outputs a substring of the string 'YN' with length 1 and offset determined by 2 - (.= 'true') -- where we use the fact that in XPath 1.0 if a Boolean value is an argument of an arithmetic operation, true() is converted to 1 and false() is converted to 0

Upvotes: 0

Tomalak
Tomalak

Reputation: 338406

You want to modify <Active> nodes, specifically.

So write templates just for them and let the identity template deal with all other nodes:

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" indent="yes" />

  <!-- <Active> with a value of 'true': switch value to 'Y' -->
  <xsl:template match="Employee//Active[. = 'true']">
    <xsl:copy>Y</xsl:copy>
  </xsl:template>

  <!-- <Active> with any other value: switch value to 'N' -->
  <xsl:template match="Employee//Active[. != 'true']">
    <xsl:copy>N</xsl:copy>
  </xsl:template>

  <!-- identity template - copy all nodes that have no better template -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
</xsl:transform>

result:

<Employees xmlns:xsd="http://www.w3.org/2001/XMLSchema"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <ListItems>
      <Employee>
         <EmployeeNo>123456</EmployeeNo>
         <FirstName>firstName</FirstName>
         <LastName>lastName</LastName>
         <Email>[email protected]</Email>
         <Active>Y</Active>
      </Employee>
  </ListItems>
</Employees>

Upvotes: 2

Related Questions