[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

Re: [xsl] Comparing attribute values with the matches() function


Subject: Re: [xsl] Comparing attribute values with the matches() function
From: Florent Georges <lists@xxxxxxxxxxxx>
Date: Mon, 7 Apr 2008 04:24:53 +0200 (CEST)

Tony Cusack wrote:

  Hi

> For example I want to run a test at the beginning of each
> execution of the stylesheet to check that the above
> mentioned business rule has been observed.

  I am not sure, but I think you want to check that there is
no @audience that contains a letter that its first @audience
that appears on an ancestor doesn't contain.  If it's the
case, I'd use instead string-to-codepoints(), and set
comparison operators to see if there is an error.

  If you only want to do a check at the beginning of your
stylesheet, I'd use a recursive template in a specific mode
that pass the letters down.  If you want to be able to get
all the descendent @audience that have an error, I would
instead use an appropriate predicate.

  The later is maybe simpler, but a naive implementation
will evaluate string-to-codepoints() several times for the
parents, while it is evaluated only once for each @audience
with the former.  But I didn't do any performance test.

  The following stylesheet shows how to do both ways.

  I don't think that's possible to write a single XPath
expression without the help of a function to introduce at
least one variable.  Maybe someone else?

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns:my="tcusack.xsl"
                version="2.0">

   <xsl:output method="text"/>

   <!-- launch both ways -->
   <xsl:template match="/">
      <xsl:apply-templates mode="check"/>
      <xsl:text>--&#10;</xsl:text>
      <xsl:value-of separator="&#10;" select="
          Publication//*/@audience[my:error-p(.)]/../@title"/>
      <xsl:text>--&#10;</xsl:text>
      <!-- add main processing... -->
   </xsl:template>

   <!-- #1 the predicate -->
   <xsl:function name="my:error-p" as="xs:boolean">
      <xsl:param name="a" as="attribute(audience)"/>
      <xsl:variable name="letters" select="string-to-codepoints($a)"/>
      <xsl:variable name="parent"  select="
          ($a/../ancestor::*/@audience)[1]/string-to-codepoints(.)"/>
      <xsl:sequence select="exists($letters[not(. = $parent)])"/>
   </xsl:function>

   <!-- #2 ignore text nodes while checking -->
   <xsl:template match="text()" mode="check"/>

   <!-- #2 the initial codepoints set -->
   <xsl:template match="Publication" priority="1" mode="check">
      <xsl:apply-templates mode="check">
         <xsl:with-param name="letters" select="
             string-to-codepoints(@audience)"/>
      </xsl:apply-templates>
   </xsl:template>

   <!-- #2 when there is no @audience, just pass the set as it is -->
   <xsl:template match="*[empty(@audience)]" mode="check">
      <xsl:param name="letters" as="xs:integer+"/>
      <xsl:apply-templates mode="check">
         <xsl:with-param name="letters" select="$letters"/>
      </xsl:apply-templates>
   </xsl:template>

   <!-- #2 compare the @audience letters to the first ancestor's
        @audience, then pass the current letters down -->
   <xsl:template match="*[exists(@audience)]" mode="check">
      <xsl:param name="letters" as="xs:integer+"/>
      <xsl:variable name="new" as="xs:integer+" select="
          string-to-codepoints(@audience)"/>
      <xsl:if test="exists($new[not(. = $letters)])">
         <xsl:value-of select="@title"/>
         <xsl:text>&#10;</xsl:text>
      </xsl:if>
      <xsl:apply-templates mode="check">
         <xsl:with-param name="letters" select="$new"/>
      </xsl:apply-templates>
   </xsl:template>

</xsl:stylesheet>

  Regards,

--drkm


























      _____________________________________________________________________________ 
Envoyez avec Yahoo! Mail. Une boite mail plus intelligente http://mail.yahoo.fr


Current Thread
Keywords