Re: [xsl] match by arbitrary number of criteria

Subject: Re: [xsl] match by arbitrary number of criteria
From: "Andrew Welch" <andrew.j.welch@xxxxxxxxx>
Date: Mon, 4 Jun 2007 09:41:31 +0100
On 6/4/07, John Horner <Horner.John@xxxxxxxxxx> wrote:
I've got XML roughly like this:

<items>
        <item>
                <name>foo</name>
                <subjects>
                        <subject>Science</subject>
                        <subject>Politics</subject>
                        <subject>History</subject>
                </subjects>
        </item>
        <item>
                <name>bar</name>
                <subjects>
                        <subject>Science</subject>
                        <subject>History</subject>
                        <subject>Art</subject>
                </subjects>
        </item>
</items>

Where each item, as you can see, is categorised.

I'm transforming them, using parameters for inclusion and exclusion,
roughly like this:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
        <xsl:param name="included" select="'Science'"/>
        <xsl:param name="excluded" select="'Politics'"/>
        <xsl:template match="//item">
                <xsl:if test="contains(subjects,$included) and
not(contains(subjects,$excluded))">
                        <xsl:value-of select="name"/>
                </xsl:if>
        </xsl:template>
</xsl:stylesheet>

Which selects "bar", because its subjects match the included string and
don't match the excluded string.

So, all well and good if I only ever have one of each, but now I need to
add more. What if I might have any number of inclusions and exclusions?
Say I had a config file like this:

<config>
        <included>
                <subject>Science</subject>
                <subject>History</subject>
        </included>
        <excluded>
                <subject>Politics</subject>
        </excluded>
</config>

Allowing an arbitrary number of inclusions and exclusions, how would I
efficiently test each item?

You can use the set comparison operators = and !=


If that config file you describe above is called "config.xml" then you
can compare each <item> with the values in the config:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>

<xsl:variable name="config" select="document('config.xml')">

<xsl:template match="/">
	<xsl:copy-of select="//item[not($config/config/included/subject !=
current()/subjects/subject)
	][not(subjects/subject = $config/config/excluded/subject)]"/>
</xsl:template>

</xsl:stylesheet>

Running this with your above input gives the output:

<item>
 <name>bar</name>
 <subjects>
   <subject>Science</subject>
   <subject>History</subject>
   <subject>Art</subject>
 </subjects>
</item>

cheers
andrew

Current Thread