Subject: Re: [xsl] Tricky inclusion match From: Dimitre Novatchev <dnovatchev@xxxxxxxxx> Date: Thu, 31 Mar 2005 15:49:25 +1000 |
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: [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 > > > > _________________________________________________________________ > Don't just search. Find. Check out the new MSN Search! > http://search.msn.click-url.com/go/onm00200636ave/direct/01/
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
RE: [xsl] Tricky inclusion match, Aron Bock | Thread | Re: [xsl] Tricky inclusion match, Karl Stubsjoen |
Re: [xsl] Testing 2 XML documents f, Mukul Gandhi | Date | [xsl] A few questions to WordML, senetex |
Month |