1

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?

DaveF
  • 113
  • 10

2 Answers2

0

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.

al.truisme
  • 450
  • 2
  • 11
  • "Need to add the namespace in the input document:" True. That was my copy/paste error. The XML doc has the namespace. – DaveF Oct 18 '22 at 14:17
  • Clearly an error somewhere as it was not in the input document that you provided. – al.truisme Oct 18 '22 at 18:49
0

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;

Martin Honnen
  • 160,499
  • 6
  • 90
  • 110
  • I'm slight confused by your comment. I'm using Saxon home edition. Are you saying it won't work with that version? As I said, it does process 'nilled' but just not correctly. I double checked by misspelling 'nilled' & it failed to produce any output at all. – DaveF Oct 18 '22 at 14:25
  • 2
    The function returns false with Saxon HE or PE, it will only give true if used with EE and schema validated input (and where the schema defines the element to be nillable). – Martin Honnen Oct 18 '22 at 14:40