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>-- </xsl:text>
<xsl:value-of separator=" " select="
Publication//*/@audience[my:error-p(.)]/../@title"/>
<xsl:text>-- </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> </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
--~------------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--