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

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


Subject: [xsl] Comparing attribute values with the matches() function
From: "Tony Cusack" <tony@xxxxxxxxxxxxxx>
Date: Mon, 7 Apr 2008 07:28:18 +1000

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]//*[@audience][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