[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

RE: Tricky inclusion match

Subject: RE: Tricky inclusion match
From: "Aron Bock" <aronbock@xxxxxxxxxxx>
Date: Tue, 29 Mar 2005 17:27:18 +0000
apply templates call template difference
Karl, here's an XSLT 1.0 solution:

My basis for this are templates from Sal Mangano's "XSLT Cookbook"; please search this list for other times I've referenced this resource, including mentioning from where to download its code.

My approach is to hold the <colors> element in a variable, and then to compare its children against those of each <picture> element, in an "intersection" operation. If we have 2 or more intersections, print:

Regards,

--A



colors.xsl
======

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:vset="http:/www.ora.com/XSLTCookbook/namespaces/vset"
extension-element-prefixes="vset">


   <xsl:import href="vset.ops.xsl"/>
   <xsl:output method="text" />


<xsl:template match="/"> <xsl:variable name="colorlist" select="/data/colors"/> <xsl:for-each select="/data/pictures/picture"> <xsl:variable name="matchcount"> <xsl:call-template name="compare"> <xsl:with-param name="node1" select="$colorlist"/> <xsl:with-param name="node2" select="."/> </xsl:call-template> </xsl:variable>

           <xsl:if test="string-length($matchcount) &gt;= 2">
               <xsl:text>picture sample #</xsl:text>
               <xsl:value-of select="@sample"/>
               <xsl:text>&#xa;</xsl:text>
           </xsl:if>
       </xsl:for-each>
   </xsl:template>


<xsl:template name="compare"> <xsl:param name="node1"/> <xsl:param name="node2"/>

       <xsl:call-template name="vset:intersection">
           <xsl:with-param name="nodes1" select="$node1//*"/>
           <xsl:with-param name="nodes2" select="$node2//*"/>
       </xsl:call-template>
   </xsl:template>


<xsl:template match="*" mode="vset:intersection"> <xsl:value-of select="'*'"/> </xsl:template>

<xsl:template match="node( ) | @*" mode="vset:element-equality">
<xsl:param name="other"/>
<xsl:if test="local-name(.) = local-name($other) and ./text() = $other/text()">
<xsl:value-of select="true()"/>
</xsl:if>
</xsl:template>


</xsl:stylesheet>



vset.ops.xsl
======

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:vset="http:/www.ora.com/XSLTCookbook/namespaces/vset">


<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<!-- The default implementation of element equality. Override in the importing
stylesheet as neccessary. -->
<xsl:template match="node( ) | @*" mode="vset:element-equality">
<xsl:param name="other"/>
<xsl:if test=". = $other">
<xsl:value-of select="true( )"/>
</xsl:if>
</xsl:template>



<!-- The default set membership test uses element equality. You will rarely need to
override this in the importing stylesheet. -->
<xsl:template match="node( ) | @*" mode="vset:member-of">
<xsl:param name="elem"/>
<xsl:variable name="member-of">
<xsl:for-each select=".">
<xsl:apply-templates select="." mode="vset:element-equality">
<xsl:with-param name="other" select="$elem"/>
</xsl:apply-templates>
</xsl:for-each>
</xsl:variable>
<xsl:value-of select="string($member-of)"/>
</xsl:template>



<!-- Compute the union of two sets using "by value" equality. -->
<xsl:template name="vset:union">
<xsl:param name="nodes1" select="/.." />
<xsl:param name="nodes2" select="/.." />
<!-- for internal use -->
<xsl:param name="nodes" select="$nodes1 | $nodes2" />
<xsl:param name="union" select="/.." />
<xsl:choose>
<xsl:when test="$nodes">
<xsl:variable name="test">
<xsl:apply-templates select="$union" mode="vset:member-of">
<xsl:with-param name="elem" select="$nodes[1]" />
</xsl:apply-templates>
</xsl:variable>
<xsl:call-template name="vset:union">
<xsl:with-param name="nodes" select="$nodes[position( ) &gt; 1]" />
<xsl:with-param name="union" select="$union | $nodes[1][not(string($test))]" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="$union" mode="vset:union" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>



<!-- Return a copy of union by default. Override in importing stylesheet to recieve
reults as a "callback"-->
<xsl:template match="/ | node( ) | @*" mode="vset:union">
<xsl:copy-of select="."/>
</xsl:template>



<!-- Compute the intersection of two sets using "by value" equality. --> <xsl:template name="vset:intersection"> <xsl:param name="nodes1" select="/.."/> <xsl:param name="nodes2" select="/.."/> <!-- For internal use --> <xsl:param name="intersect" select="/.."/>

<xsl:choose>
<xsl:when test="not($nodes1)">
<xsl:apply-templates select="$intersect" mode="vset:intersection"/>
</xsl:when>
<xsl:when test="not($nodes2)">
<xsl:apply-templates select="$intersect" mode="vset:intersection"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="test1">
<xsl:apply-templates select="$nodes2" mode="vset:member-of">
<xsl:with-param name="elem" select="$nodes1[1]"/>
</xsl:apply-templates>
</xsl:variable>
<xsl:variable name="test2">
<xsl:apply-templates select="$intersect" mode="vset:member-of">
<xsl:with-param name="elem" select="$nodes1[1]"/>
</xsl:apply-templates>
</xsl:variable>
<xsl:choose>
<xsl:when test="string($test1) and not(string($test2))">
<xsl:call-template name="vset:intersection">
<xsl:with-param name="nodes1" select="$nodes1[position( ) &gt; 1]"/>
<xsl:with-param name="nodes2" select="$nodes2"/>
<xsl:with-param name="intersect" select="$intersect | $nodes1[1]"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="vset:intersection">
<xsl:with-param name="nodes1" select="$nodes1[position( ) &gt; 1]"/>
<xsl:with-param name="nodes2" select="$nodes2"/>
<xsl:with-param name="intersect" select="$intersect"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>



<!-- Return a copy of intersection by default. Override in importing stylesheet to
recieve results as a "callback"-->
<xsl:template match="/ | node( ) | @*" mode="vset:intersection">
<xsl:copy-of select="."/>
</xsl:template>



<!-- Compute the differnce between two sets (node1 - nodes2) using "by value" equality. -->
<xsl:template name="vset:difference">
<xsl:param name="nodes1" select="/.."/>
<xsl:param name="nodes2" select="/.."/>
<!-- For internal use -->
<xsl:param name="difference" select="/.."/>


<xsl:choose>
<xsl:when test="not($nodes1)">
<xsl:apply-templates select="$difference" mode="vset:difference"/>
</xsl:when>
<xsl:when test="not($nodes2)">
<xsl:apply-templates select="$nodes1" mode="vset:difference"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="test1">
<xsl:apply-templates select="$nodes2" mode="vset:member-of">
<xsl:with-param name="elem" select="$nodes1[1]"/>
</xsl:apply-templates>
</xsl:variable>
<xsl:variable name="test2">
<xsl:apply-templates select="$difference" mode="vset:member-of">
<xsl:with-param name="elem" select="$nodes1[1]"/>
</xsl:apply-templates>
</xsl:variable>
<xsl:choose>
<xsl:when test="string($test1) or string($test2)">
<xsl:call-template name="vset:difference">
<xsl:with-param name="nodes1" select="$nodes1[position( ) &gt; 1]"/>
<xsl:with-param name="nodes2" select="$nodes2"/>
<xsl:with-param name="difference" select="$difference"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="vset:difference">
<xsl:with-param name="nodes1" select="$nodes1[position( ) &gt; 1]"/>
<xsl:with-param name="nodes2" select="$nodes2"/>
<xsl:with-param name="difference" select="$difference | $nodes1[1]"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>



<!--
Computes the differnce between two sets (node1 - nodes2) using "by value" equality.
"Short-circuit"-s processing at the first difference-node.
-->
<xsl:template name="vset:difference-short-circuit">
<xsl:param name="nodes1" select="/.."/>
<xsl:param name="nodes2" select="/.."/>
<!-- For internal use -->
<xsl:param name="difference" select="/.."/>


<xsl:choose>
<xsl:when test="not($nodes1)">
<xsl:apply-templates select="$difference" mode="vset:difference"/>
</xsl:when>
<xsl:when test="not($nodes2)">
<xsl:apply-templates select="$nodes1" mode="vset:difference"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="test1">
<xsl:apply-templates select="$nodes2" mode="vset:member-of">
<xsl:with-param name="elem" select="$nodes1[1]"/>
</xsl:apply-templates>
</xsl:variable>
<xsl:variable name="test2">
<xsl:apply-templates select="$difference" mode="vset:member-of">
<xsl:with-param name="elem" select="$nodes1[1]"/>
</xsl:apply-templates>
</xsl:variable>
<xsl:choose>
<xsl:when test="string($test1) or string($test2)">
<xsl:call-template name="vset:difference-short-circuit">
<xsl:with-param name="nodes1" select="$nodes1[position( ) &gt; 1]"/>
<xsl:with-param name="nodes2" select="$nodes2"/>
<xsl:with-param name="difference" select="$difference"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="vset:difference-short-circuit">
<xsl:with-param name="nodes1" select="/.."/>
<xsl:with-param name="nodes2" select="$nodes2"/>
<xsl:with-param name="difference" select="$difference | $nodes1[1]"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>



<!-- Return a copy of difference by default. Override in importing stylesheet to
recieve results as a "callback"-->
<xsl:template match="/ | node( ) | @*" mode="vset:difference">
<xsl:copy-of select="."/>
</xsl:template>


</xsl:stylesheet>





From: Karl Stubsjoen <kstubs@xxxxxxxxx>
Reply-To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject:  Tricky inclusion match
Date: Tue, 29 Mar 2005 07:55:43 -0700

Okay,
Lets say you have a set of colors and you have a whole bunch of
pictures and you want to match on all pictures who have one or more of
the given colors but you have to at least match on 2 of them (unique,
so not red and red - so a picture could list red twice but that would
not be a match).  I'm trying to use keys and grouping to solve this
but thinking that I might be making this more difficult.  At any rate,
I'm stuck and would appreciate some help : )

Sample Data (expected results below):

<data>
    <colors>
    	<color>red</color>
    	<color>blue</color>
    	<color>fucia</color>
    	<color>violet</color>
    </colors>
    <pictures>
    	<picture sample="1">
        	<color>black</color>
        	<color>grey</color>
        	<color>white</color>
        </picture>
    	<picture sample="2">
        	<color>red</color>
        	<color>green</color>
        	<color>brown</color>
        	<color>blue</color>
        </picture>
    	<picture sample="3">
        	<color>purple</color>
        	<color>orange</color>
        </picture>
    	<picture sample="4">
        	<color>blue</color>
        	<color>green</color>
        	<color>red</color>
        </picture>
    	<picture sample="5">
        	<color>fucia</color>
        	<color>green</color>
        	<color>violet</color>
        </picture>
    	<picture sample="6">
        	<color>red</color>
        	<color>brown</color>
        	<color>red</color>
        </picture>
    </pictures>
</data>

Expected Results (picture matches based on 2 or more colors used and
listed in colors above)

picture sample #2
picture sample #4
picture sample #5


_________________________________________________________________
Dont just search. Find. Check out the new MSN Search! http://search.msn.click-url.com/go/onm00200636ave/direct/01/


Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.