Add attribute xsl:nil=true on empty elements using XSLT

What?
An article on how to declare an XML element as NULL using the attribute "xsi:nil". I'm going to use a very short example by providing a blank date of birth value:
copyraw
-- What I have:
<DATE_OF_BIRTH />
<DATE_OF_BIRTH_EUROPEANFORMAT>//</DATE_OF_BIRTH_EUROPEANFORMAT>

-- What I want:
<DATE_OF_BIRTH xsi:nil="true" />
<DATE_OF_BIRTH_EUROPEANFORMAT xsi:nil="true" />
  1.  -- What I have: 
  2.  <DATE_OF_BIRTH /> 
  3.  <DATE_OF_BIRTH_EUROPEANFORMAT>>//</DATE_OF_BIRTH_EUROPEANFORMAT> 
  4.   
  5.  -- What I want: 
  6.  <DATE_OF_BIRTH xsi:nil="true" /> 
  7.  <DATE_OF_BIRTH_EUROPEANFORMAT xsi:nil="true" /> 

Why?
Outputting from SITS:Vision to our staging environment, the application would only output blank values using single tags so we had to find a place to introduce it. On strings this has little worth, but on dates which could be NULL, this was necessary (unless we interpreted dates as strings which we don't want to do):
copyraw
-- SITS Output: Option 1
<stu_dob></stu_dob>

-- SITS Output: Option 2
<stu_dob />

-- but not
<stu_dob xsi:nil="true" />
  1.  -- SITS Output: Option 1 
  2.  <stu_dob></stu_dob> 
  3.   
  4.  -- SITS Output: Option 2 
  5.  <stu_dob /> 
  6.   
  7.  -- but not 
  8.  <stu_dob xsi:nil="true" /> 
This doesn't tell us if the element is just an empty string or null. This doesn't have much affect on point-to-point conversions and strings but what if the value is blank and I try to convert that date of birth from SQL format (yyyy-mm-dd) to European format (dd/mm/yyyy)? See the following:
copyraw
<xsl:stylesheet
	version="1.0"
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

	<xsl:output method="xml" indent="yes"/>
	<xsl:template match="exchange/stu">
		<STUDENT>
			<xsl:for-each select="stu.srs">
				<DATE_OF_BIRTH>
					<xsl:value-of select="stu_dob"/>
				</DATE_OF_BIRTH>

				<DATE_OF_BIRTH_EUROPEANFORMAT>
					<xsl:value-of select="concat(substring(stu_dob, 9, 2),'/',substring(stu_dob, 6, 2),'/',substring(stu_dob, 1, 4))"/>
				</DATE_OF_BIRTH_EUROPEANFORMAT>
			</xsl:for-each>
		</STUDENT>
	</xsl:template>
</xsl:stylesheet>


-- assuming value of DATE_OF_BIRTH is blank or null yields
<STUDENT xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<DATE_OF_BIRTH />
	<DATE_OF_BIRTH_EUROPEANFORMAT>//</DATE_OF_BIRTH_EUROPEANFORMAT>
</STUDENT>

-- errors
  1.  <xsl:stylesheet 
  2.      version="1.0" 
  3.      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
  4.   
  5.      <xsl:output method="xml" indent="yes"/> 
  6.      <xsl:template match="exchange/stu"> 
  7.          <STUDENT> 
  8.              <xsl:for-each select="stu.srs"> 
  9.                  <DATE_OF_BIRTH> 
  10.                      <xsl:value-of select="stu_dob"/> 
  11.                  </DATE_OF_BIRTH> 
  12.   
  13.                  <DATE_OF_BIRTH_EUROPEANFORMAT> 
  14.                      <xsl:value-of select="concat(substring(stu_dob, 9, 2),'/',substring(stu_dob, 6, 2),'/',substring(stu_dob, 1, 4))"/> 
  15.                  </DATE_OF_BIRTH_EUROPEANFORMAT> 
  16.              </xsl:for-each> 
  17.          </STUDENT> 
  18.      </xsl:template> 
  19.  </xsl:stylesheet> 
  20.   
  21.   
  22.  -- assuming value of DATE_OF_BIRTH is blank or null yields 
  23.  <STUDENT xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
  24.      <DATE_OF_BIRTH /> 
  25.      <DATE_OF_BIRTH_EUROPEANFORMAT>>//</DATE_OF_BIRTH_EUROPEANFORMAT> 
  26.  </STUDENT> 
  27.   
  28.  -- errors 

How?
I could correct this using SSIS but with all the data in XML, we might as well stick with the technology and we're going to keep our XSLT with some slight modifications. First let's look at the XML output from SITS (this is a cut down version for demonstration purposes):
copyraw
<exchange>
	<stu>
		<stu.srs>
			<stu_code>1234567</stu_code>
			<stu_fnm1>JOEL</stu_fnm1>
			<stu_surn>LIPMAN</stu_surn>
			<stu_dob />
		</stu.srs>
	</stu>
</exchange>
  1.  <exchange> 
  2.      <stu> 
  3.          <stu.srs> 
  4.              <stu_code>1234567</stu_code> 
  5.              <stu_fnm1>JOEL</stu_fnm1> 
  6.              <stu_surn>LIPMAN</stu_surn> 
  7.              <stu_dob /> 
  8.          </stu.srs> 
  9.      </stu> 
  10.  </exchange> 
Two things to do really:
  1. Add the xmlns:xsi namespace in the xsl:stylesheet tag so that "xsi:nil=true" is valid.
  2. Test for a string length of greater than 0 (not blank) and change the attribute of the element so that it's tag displays "xsi:nil=true".
If...then...else... will be emulated by the XSLT choose...when...test...otherwise:
copyraw
<xsl:stylesheet
	version="1.0"
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

	<xsl:output method="xml" indent="yes"/>
	<xsl:template match="exchange/stu">

		<!-- note the addition of the xmlns:xsi namespace //-->
		<STUDENT xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
			<xsl:for-each select="stu.srs">
				<DATE_OF_BIRTH>
					<!-- adding a bit of conditionality //-->
					<xsl:choose>
						<xsl:when test="string-length(normalize-space(stu_dob))>0">
							<xsl:value-of select="stu_dob"/>
						</xsl:when>
						<xsl:otherwise>
							<xsl:attribute name="xsi:nil">true</xsl:attribute>
							<xsl:value-of select="stu_dob"/>
						</xsl:otherwise>
					</xsl:choose>
				</DATE_OF_BIRTH>

				<DATE_OF_BIRTH_EUROPEANFORMAT>
					<xsl:choose>
						<xsl:when test="string-length(normalize-space(stu_dob))>0">
							<xsl:value-of select="concat(substring(stu_dob, 9, 2),'/',substring(stu_dob, 6, 2),'/',substring(stu_dob, 1, 4))"/>
						</xsl:when>
						<xsl:otherwise>
							<xsl:attribute name="xsi:nil">true</xsl:attribute>
							<xsl:value-of select="stu_dob"/>
						</xsl:otherwise>
					</xsl:choose>
				</DATE_OF_BIRTH_EUROPEANFORMAT>
			</xsl:for-each>
		</STUDENT>
	</xsl:template>
</xsl:stylesheet>
  1.  <xsl:stylesheet 
  2.      version="1.0" 
  3.      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
  4.   
  5.      <xsl:output method="xml" indent="yes"/> 
  6.      <xsl:template match="exchange/stu"> 
  7.   
  8.          <!-- note the addition of the xmlns:xsi namespace //--> 
  9.          <STUDENT xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
  10.              <xsl:for-each select="stu.srs"> 
  11.                  <DATE_OF_BIRTH> 
  12.                      <!-- adding a bit of conditionality //--> 
  13.                      <xsl:choose> 
  14.                          <xsl:when test="string-length(normalize-space(stu_dob))>0"> 
  15.                              <xsl:value-of select="stu_dob"/> 
  16.                          </xsl:when> 
  17.                          <xsl:otherwise> 
  18.                              <xsl:attribute name="xsi:nil">true</xsl:attribute> 
  19.                              <xsl:value-of select="stu_dob"/> 
  20.                          </xsl:otherwise> 
  21.                      </xsl:choose> 
  22.                  </DATE_OF_BIRTH> 
  23.   
  24.                  <DATE_OF_BIRTH_EUROPEANFORMAT> 
  25.                      <xsl:choose> 
  26.                          <xsl:when test="string-length(normalize-space(stu_dob))>0"> 
  27.                              <xsl:value-of select="concat(substring(stu_dob, 9, 2),'/',substring(stu_dob, 6, 2),'/',substring(stu_dob, 1, 4))"/> 
  28.                          </xsl:when> 
  29.                          <xsl:otherwise> 
  30.                              <xsl:attribute name="xsi:nil">true</xsl:attribute> 
  31.                              <xsl:value-of select="stu_dob"/> 
  32.                          </xsl:otherwise> 
  33.                      </xsl:choose> 
  34.                  </DATE_OF_BIRTH_EUROPEANFORMAT> 
  35.              </xsl:for-each> 
  36.          </STUDENT> 
  37.      </xsl:template> 
  38.  </xsl:stylesheet> 
copyraw
-- yields: assuming value of DATE_OF_BIRTH is blank or null yields
<STUDENT xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<DATE_OF_BIRTH xsi:nil="true" />
	<DATE_OF_BIRTH_EUROPEANFORMAT xsi:nil="true" />
</STUDENT>
  1.  -- yields: assuming value of DATE_OF_BIRTH is blank or null yields 
  2.  <STUDENT xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
  3.      <DATE_OF_BIRTH xsi:nil="true" /> 
  4.      <DATE_OF_BIRTH_EUROPEANFORMAT xsi:nil="true" /> 
  5.  </STUDENT> 

Done!

Category: XML Stylesheet Language Transformations :: Article: 578

Credit where Credit is Due:


Feel free to copy, redistribute and share this information. All that we ask is that you attribute credit and possibly even a link back to this website as it really helps in our search engine rankings.

Disclaimer: The information on this website is provided without warranty and any content is merely the opinion of the author. Please try to test in development environments prior to adapting them to your production environments. The articles are written in good faith and, at the time of print, are working examples used in a commercial setting.

Thank you for visiting and, as always, we hope this website was of some use to you!

Kind Regards,

Joel Lipman
www.joellipman.com

Related Articles

Joes Revolver Map

Joes Word Cloud

Accreditation

Badge - Certified Zoho Creator Associate
Badge - Certified Zoho Creator Associate

Donate & Support

If you like my content, and would like to support this sharing site, feel free to donate using a method below:

Paypal:
Donate to Joel Lipman via PayPal

Bitcoin:
Donate to Joel Lipman with Bitcoin - Valid till 8 May 2022 bc1qjtp4l4ra452wzvuk9a45yfj82zkahsyy2z379y
© 2022 Joel Lipman .com. All Rights Reserved.