This is the mail archive of the xsl-list@mulberrytech.com mailing list .


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: producing three sets of output from one file


Eric,

What appears below is *not* a beginner's solution, but it's an interesting 
approach to your problem. While less evidently straightforward than Joerg's 
solution, it has the virtue of a more complete modeling of the problem, 
making it more flexible and extensible.

You start with a lookup table in your stylesheet:

<my:privileges xmlns:my="mynamespace.com"> <!-- put the table in a local 
namespace -->
   <rights group="C">
     <rights group="B">
       <rights group="A"/>
     </rights>
   </rights>
</my:privileges>At 12:23 PM 3/29/2002, you wrote:

Notice that the design of these nodes reflects the relations of the groups: 
that C can see B's and A's stuff, that B can see A's stuff but not C's, and 
that A can only see A's stuff.

Next, you create a utility variable just so you can pick any of these nodes 
out easily:

<xsl:variable name="rightsgroups" 
select="document('')/*/my:privileges//rights"/>

Okay, that's "advanced": it queries the stylesheet itself with the 
document('') function, then traverses down via an XPath to collect all the 
rights elements inside your my:privileges node. (Actually you could do 
without this variable, rolling it into the next one, but breaking it out 
makes it a bit easier to understand.)

Next, you want to locate the *subset* of these nodes in which you are 
actually interested. You do this with a parameter, which you can pass into 
the stylesheet at run time:

<xsl:param name="thisgroup" select="'A'"/>

(This declaration sets the default to 'A' but it could be the empty string 
'' if you wanted to default to no permissions, or 'C' for the highest, 
whatever.)

And then,

<xsl:variable name="theseprivileges"
               select="$rightsgroups[@group=$thisgroup]//rights/@group"/>

This fancy expression means "all the 'group' attribute nodes [@group] on 
any rights nodes that are descendants or self of the node from 
$rightsgroups whose @group attribute equals $thisgroup".

The long way of writing this expression would look like:

$rightsgroups[@group=$thisgroup]/descendant-or-self::rights/@group

This way, if your parameter is 'C' you'll get the @group attribute on the C 
rights node *along with the @group attributes* on its descendants, B and A; 
but if $thisgroup is 'A', you'll only get the group='A' attribute node 
(since its 'rights' element has no descendants).

Now, you proceed as Joerg did, except you can use the equality rule for 
nodesets and strings to collect nodes from your source file that are 
permitted to each group:

<xsl:apply-templates select="article[@audience = $theseprivileges]"/>

Remember that $theseprivileges is a *collection* of attribute nodes: in 
your case, if $thisgroup is A, it's a lone @group attribute with value 'A'; 
but if $thisgroup is C, it's a collection of @group attributes, with values 
'A', 'B', 'C'.

Since a string is equal to a nodeset if its value is the value of *any* of 
the nodes in the set, you can see you'll get your A, B, and C articles when 
your group is C, but only your A articles when your group is A.

While it's obscure (and if you use this code, *document* it for the poor 
XSLT beginner who takes over your job when you move up), you can see how 
powerful and extensible this approach is. All you need to do is extend your 
lookup table to accommodate for more groups and their relations:

<my:privileges>
   <rights group="admin">
     <rights group="superusers">
       <rights group="daytimers">
          <rights group="guests"/>
          <rights group="gamers"/>
       </rights>
       <rights group="nighttimers">
          <rights="gamers"/>
       </rights>
     </rights>
   </rights>
</my:privileges>

And it works with any strings as group labels, not just one-character 
strings. Here, the admin group gets all articles, the daytimers get their 
own stuff plus guests' and gamers' articles, but gamers get only gamers' 
stuff. Nightimers get their stuff plus gamers'; the appearance of one group 
in several places is not a problem here.

I know that's more than you asked for, but your problem was interesting 
enough that I thought it was worth sketching out. While not, as you 
requested, a beginner's solution, it does demonstrate some things that 
beginners (or advanced beginners) might like to know about:

1. using a local (or remote) lookup table for very flexible configuration 
(with the document() function for access)
2. XPath expressions (in your variable declarations etc.) to select *and 
filter* nodes
3. testing a string against a node set -- true when *any* node contains the 
string (a very useful feature once you're aware of it)
4. using tree structures to represent more complex relations than simple 
linear relations (such as the relations in a permissions hierarchy)

I hope that's fun, anyway--

Cheers,
Wendell

> > I'm trying produce three sets of output from one set of data, each of
> > which are subsets of the preceding.  That is, I have:
> >     <article audience="A">stuff here</article>
> >     <article audience="B">stuff here</article>
> >     <article audience="C">stuff here</article>
> >     <article audience="A">stuff here</article>
> >     <article audience="A">stuff here</article>
> >
> > For audience A, I want to include only the A articles; for audience B, I
> > want to include both A&B articles, and for audience C, I want to include
> > them all. I was preparing to just create three different XSL files and
> > then use Instant Saxon to transform with each XSL. However, since the
> > output is formatted identically, I suspect there's a much more elegant
> > way to do it (perhaps passing some parameter when compiling?), but I'm
> > not sure what I would do.
> >
> > If this is explainable to a beginner, I'd appreciate any help.  (Or if
> > this is beyond a beginner's ability, I'd appreciate someone telling me
> > that... and I'll do the easy three files as I planned and come back to
> > this at some point in the future.)


======================================================================
Wendell Piez                            mailto:wapiez@mulberrytech.com
Mulberry Technologies, Inc.                http://www.mulberrytech.com
17 West Jefferson Street                    Direct Phone: 301/315-9635
Suite 207                                          Phone: 301/315-9631
Rockville, MD  20850                                 Fax: 301/315-8285
----------------------------------------------------------------------
   Mulberry Technologies: A Consultancy Specializing in SGML and XML
======================================================================


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]