[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message] Re: Tricky inclusion match
On Thu, 31 Mar 2005 07:40:59 -0700, Karl Stubsjoen <kstubs@xxxxxxxxx> wrote: > 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. Yes, as the picture id=6 from your original source xml document was not selected, too. Just try it and also try to understand what the XPath expression specifies. > > 2) xxx:node-set() - what does this mean, what are you refering to? I saw in the long thread that somebody was discussing solutions that requires the xxx:node-set() extension function. In my solution there isn't a (need to) reference to any extension function. "xxx" is an abbreviation to a prefix bound to the corresponding vendor-defined namespace in which the particular implementation of the node-set() extension function is defined. > > 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? There must be something in Dave's FAQ. I remember 2-3 very nice entries by Michael Kay on this subject. Cheers, Dimitre. > > Karl > > On Thu, 31 Mar 2005 15:49:25 +1000, Dimitre Novatchev > <dnovatchev@xxxxxxxxx> wrote: > > 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
|