views:

292

answers:

4

I have an XML document and associated schema that defines several attributes as having the xs:boolean type. The lexical values for xs:boolean are true, false, 1, and 0, so it seems that to correctly select attributes with a particular boolean value I'd have to write something like:

@attribute='true' or @attribute='1'

or

@attribute='false' or @attribute='0'

This seems verbose.

You might expect something like boolean(@attribute) to work, but the boolean function has different semantics.

Is there a better way? Is this something that a schema-aware processor would help with?

+1  A: 

Your options may depend upon which XPath processor you're using. For example, the Microsoft stuff allows you to define JavaScript functions that you could use to implement the "boolean(@attribute)" pattern. I don't know if other engines may have similar support available.

Otherwise I suspect you are stuck with having to check for both 'true' and '1'.

Hopefully someone else has a better answer.

Phil
+1  A: 

Using XPath alone the expression you propose is as close as it gets. There are different ways of doing the same check, but all of them would lead to a longer and more complicated expression and conceal the intent more.

I don't think there is a schema-aware processor, XML schema is not connected to XSLT and it would not make much sense to build support for it into a processor, IMHO. The language is defined, and extensions are the accepted standard way of adding functionality.

If the library you use supports the EXSL extension functions, you could write a semi-portable mechanism to abstract the boolean check into a function, or you could use vendor-specific extensions like MSXSL to the same.

I think it is best to stay with the expression you have. It is not convoluted, only a bit verbose.

Tomalak
+1  A: 

In addition to the solutions proposed by Phil and Tomalak, I discovered that XPath 2.0 provides a few alternatives:

@attribute=('true','1')
string(@attribute) cast as xs:boolean

And finally, XPath 2.0 does provide schema-aware processing, which means that if everything is in alignment, you should be able to write:

data(@attribute)

But schema-aware processors seem hard to come by. The most popular seems to be the non-free commercial variant of saxon, which costs £300. So for now I'm using @attribute=('true','1').

John
A: 

I use a simple named template that does the verbose check and tweak it as needed to handle legacy systems (e.g. some fields may use "Y"/"N", some "True"/"False", others 1/0) and dump the value into a variable. It's not the most elegant approach, but if you're using XPath 1.0, don't have EXSLT support, and can't (or don't want to) utilize outside script calls, it works consistently and can be tweaked as needed.

<xsl:template name="CleanupBool">
 <xsl:param name="val" />
 <xsl:choose>
  <xsl:when test="$val='1'">1</xsl:when>
  <xsl:when test="$val='true'">1</xsl:when>
  <xsl:when test="$val='True'">1</xsl:when>
  <xsl:when test="$val='TRUE'">1</xsl:when>
  <xsl:when test="$val='T'">1</xsl:when>
  <xsl:when test="$val='Y'">1</xsl:when>
  <xsl:otherwise>0</xsl:otherwise>
 </xsl:choose>
</xsl:template>

Usage:

<xsl:variable name="enabled">
 <xsl:call-template name="CleanupBool">
  <xsl:with-param name="val" select="IS_ENABLED"/>
 </xsl:call-template>
</xsl:variable>
pdwetz