[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: "Michael Kay" <mike@xxxxxxxxxxxx>
Date: Mon, 7 Apr 2008 10:29:31 +0100

Firstly, this:

@audience=.//*[@audience]/@audience

is the same as this:

@audience=.//*/@audience 

because if an element doesn't have an @audience attribute, it will be
ignored anyway.

> The expression I need will be similar but require only that 
> the two @audience values share at least one audience identifier.

I would write a function:

<xsl:function name="f:overlaps" as="xs:boolean">
  <xsl:param name="a1" as="attribute(audience)"/>
  <xsl:param name="a2" as="attribute(audience)"/>
  <xsl:sequence select="string-to-codepoints($a1) =
string-to-codepoints($a2)"/>
</xsl:function>

(The "=" test, remember, tests whether any item in the first sequence is
equal to any item in the second sequence).

Then the condition becomes

test="some $d in .//*/@audience satisfies f:overlaps(@audience, $d)"


Michael Kay
http://www.saxonica.com/

> -----Original Message-----
> From: Tony Cusack [mailto:tony@xxxxxxxxxxxxxx] 
> Sent: 06 April 2008 22:28
> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> Subject: [xsl] Comparing attribute values with the matches() function
> 
> Hello XSL list,
>  
> I am having difficulty (with my very basic XSLT skills) 
> devising a test to compare attribute values. Hope you may be 
> able to help.
>  
> My application filters XML content for multiple audiences 
> identified simply as A, B, C etc potentially up to Z. The 
> source is flagged with an @audience value such as 'ABC' to 
> indicate that it is relevant to those three audiences. As one 
> descends through the document the content becomes more 
> specific. The following snippet illustrates:
>  
> <Publication title="Demo publication" audience="ABC">
>    <Topic title="Level 1 ABC">
>     <BodyText>Level 1 Content shared by all 3 audiences.</BodyText>
>     <Topic title="Level 2 ABC">
>      <BodyText>Level 2 Content shared by all audiences.</BodyText>
>      <Topic title="Level 3 ABC">
>       <BodyText>Level 3 Content shared by all audiences.</BodyText>
>      </Topic>
>      <Topic title="Level 3 AB" audience="AB">
>       <BodyText>Level 3 Content shared by AB audiences.</BodyText>
>      </Topic>
>      <Topic title="Level 3 BC" audience="BC">
>       <BodyText>Level 3 Content shared by BC audiences.</BodyText>
>      </Topic>
>      <Topic title="Level 3 AC" audience="AC">
>       <BodyText>Level 3 Content shared by AC audiences.</BodyText>
>      </Topic>
>      <Topic title="Level 3 A" audience="A">
>       <BodyText>Level 3 Audience A only content.</BodyText>
>      </Topic>
>     </Topic>
>    </Topic>
> </Publication>
>  
> Note that @audience is DTD optional everywhere except 
> Publication, but, as a business rule, should only ever occur 
> at the point where @audience narrows down.
>  
> To filter the content I run my stylesheet once for each 
> audience with a global variable ($config) set to that 
> audience's identifier, and use the
> contains() function to compare @audience values with the 
> global variable.
> For example:
>  
> Topic[(contains(@audience, $config)) or (not(@audience) and 
> ancestor::*[@audience][1][contains(@audience,$config)])]>
>  
> For other purposes however I need to compare @audience values 
> with each other rather than a global variable. 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. The contains() function won't do the trick 
> because, for example, ABC doesn't 'contain' AC in the relevant sense.
>  
> I believe the XSLT 2 matches() function will achieve the 
> desired result but I'm afraid that when it comes to mixing 
> XPath expressions with Regex it all becomes too much for me.
>  
> To give you a better idea of my approach here is an 
> expression which works for the = operator.
>  
> <xsl:when 
> test="//*[@audience=.//*[@audience]/@audience]"><xsl:value-of
> select="//*[@audience=.//*[@audience]/@audience][1]//*[@audien
> ce][1]/@title"
> /></xsl:when>
>  
> In English that's "When any element has a descendant with 
> @audience equal to its (the ancestor's) own @audience, output 
> the @title of the first descendant instance of the first 
> ancestor instance".
>  
> The expression I need will be similar but require only that 
> the two @audience values share at least one audience identifier.
>  
> I am using Saxon b9-0-0-2j.
>  
> Thanks very much,
> Tony Cusack.


Current Thread
Keywords