[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: Dimitre Novatchev <dnovatchev@xxxxxxxxx>
Date: Thu, 31 Mar 2005 15:49:25 +1000
xsl select union
On Tue, 29 Mar 2005 17:27:18 +0000, Aron Bock <aronbock@xxxxxxxxxxx> wrote:
> 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:

Seems a little bit too long.

This transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 
 <xsl:output omit-xml-declaration="yes"/>
 
 <xsl:variable name="vColors" select="/*/colors"/>

  <xsl:template match="/">
    <xsl:for-each select="/*/*/picture">
      <xsl:if test="count($vColors/*[. = current()/color]) >= 2">
        <xsl:value-of select="concat('Picture Id=', @sample, '&#xA;')"/>
      </xsl:if>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

when performed against the originally posted source xml document,
produces the wanted result:

Picture Id=2
Picture Id=4
Picture Id=5


This is really simple. No xxx:node-set() has been used.

Cheers,
Dimitre Novatchev


> 
> 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) >= 2">
>                <xsl:text>picture sample #</xsl:text>
>                <xsl:value-of select="@sample"/>
>                <xsl:text>
> </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(  ) > 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(  ) >
> 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(  ) >
> 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(  ) >
> 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(  ) >
> 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(  ) >
> 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
> >
> 
> _________________________________________________________________
> Don't 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.