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: Please note that the information provided on this website is intended for informational purposes only and does not represent a warranty. The opinions expressed are those of the author only. We recommend testing any solutions in a development environment before implementing them in production. The articles are based on our good faith efforts and were current at the time of writing, reflecting our practical experience 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 bc1qf6elrdxc968h0k673l2djc9wrpazhqtxw8qqp4

Ethereum:
Donate to Joel Lipman with Ethereum 0xb038962F3809b425D661EF5D22294Cf45E02FebF
© 2024 Joel Lipman .com. All Rights Reserved.