Test for xsi:nil="true"

286 views Asked by At

I wish to test for xsi:nil="true".

I'm using the replies from kjhughes & Michael Kay in these posts, respectively.

How to implement if-else statement in XSLT?

How do I check if XML value is nil in XSLT

XML:

<OSM>
    <EstablishmentDetail>
         <RatingValue>5</RatingValue>
         <RatingDate>2008-05-15</RatingDate>
    </EstablishmentDetail>
    <EstablishmentDetail>
         <RatingValue>AwaitingInspection</RatingValue>
         <RatingDate xsi:nil="true"/>
    </EstablishmentDetail>
</OSM>

A snip of the XSL:

<xsl:template>
"Value": "<xsl:value-of select="if (nilled(RatingDate)) then RatingValue else 'XX' "/>",
</xsl:template>

It's producing output but both are 'XX'. Is it just a syntax error?

2

There are 2 answers

2
al.truisme On

Need to add the namespace in the input document:

<OSM xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <EstablishmentDetail>
         <RatingValue>5</RatingValue>
         <RatingDate>2008-05-15</RatingDate>
    </EstablishmentDetail>
    <EstablishmentDetail>
         <RatingValue>AwaitingInspection</RatingValue>
         <RatingDate xsi:nil="true"/>
    </EstablishmentDetail>
</OSM>

I'm not getting the right value out of the standard fn:nilled() function hence substituted a user function:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet 
  version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:l="local:functions">
  
  <xsl:output method="xml" indent="yes" />

  <xsl:template match="/">
    <RatingValues>
      <xsl:for-each select="//EstablishmentDetail">
        <EstablishmentDetail index="{position()}" >
          <RatingValue>
            <xsl:value-of select="('XX'[l:nilled(current()/RatingDate) ], 
                                    current()/RatingValue)[1]" />
          </RatingValue>
          <Nilled>
            <xsl:value-of select="nilled(RatingDate)" />
          </Nilled>          
        </EstablishmentDetail>
      </xsl:for-each>
    </RatingValues>
  </xsl:template>
  
  <xsl:function name="l:nilled" as="xs:boolean" >
    <xsl:param name="e" as="element()" />
    
    <xsl:sequence select="exists($e/@xsi:nil) and $e/@xsi:nil eq 'true'" />
  </xsl:function>
  
</xsl:stylesheet>

which produces:


<?xml version="1.0" encoding="UTF-8"?>
<RatingValues xmlns:l="local:functions" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <EstablishmentDetail index="1">
      <RatingValue>5</RatingValue>
      <Nilled>false</Nilled>
   </EstablishmentDetail>
   <EstablishmentDetail index="2">
      <RatingValue>XX</RatingValue>
      <Nilled>false</Nilled>
   </EstablishmentDetail>
</RatingValues>

The Nilled elements in the output just to show that I'm getting false for both cases.

2
Martin Honnen On

The function https://www.w3.org/TR/xpath-functions/#func-nilled is meant to work with schema-aware XSLT and validated input i.e. if you use Saxon EE you can expect it to do its job:

In practice, the function returns true only for an element node that has the attribute xsi:nil="true" and that is successfully validated against a schema that defines the element to be nillable;