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" />
- -- 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" />
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
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:
-- SITS Output: Option 1 <stu_dob></stu_dob> -- SITS Output: Option 2 <stu_dob /> -- but not <stu_dob xsi:nil="true" />
- -- SITS Output: Option 1
- <stu_dob></stu_dob>
- -- SITS Output: Option 2
- <stu_dob />
- -- but not
- <stu_dob xsi:nil="true" />
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
- <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
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
Two things to do really:<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>
- <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>
- Add the xmlns:xsi namespace in the xsl:stylesheet tag so that "xsi:nil=true" is valid.
- 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".
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>
- <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>
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>
- -- 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>
Done!
Category: XML Stylesheet Language Transformations :: Article: 578