|
[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message] Re: Tricky inclusion match
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, '
')"/>
</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/
|
PURCHASE STYLUS STUDIO ONLINE TODAY!Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced! Download The World's Best XML IDE!Accelerate XML development with our award-winning XML IDE - Download a free trial today! Subscribe in XML format
|

Cart








