xsl-list
[Top] [All Lists]

Re: Tricky inclusion match

2005-03-31 07:40:59
Thanks Dimitre for another approach.  2 questions:

1)  if a picture contains the following colors: red, red, maroon where
red is the only color which qualifies as a match, will your test catch
this?  In otherwords, this picture does not qualify.

2) xxx:node-set() - what does this mean, what are you refering to?

Something I've heard a lot of on this list is the occasional term
"efficiency".  Is there a list of things to NOT do, recommended
practices, etc in regards to developing an efficient stylesheet?

Karl


On Thu, 31 Mar 2005 15:49:25 +1000, Dimitre Novatchev
<dnovatchev(_at_)gmail(_dot_)com> wrote:
On Tue, 29 Mar 2005 17:27:18 +0000, Aron Bock 
<aronbock(_at_)hotmail(_dot_)com> 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(_at_)gmail(_dot_)com>
Reply-To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
Subject: [xsl] 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

--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: 
<mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--


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


--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: 
<mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--



--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: 
<mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--



--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--



<Prev in Thread] Current Thread [Next in Thread>