Subject: Re: [xsl] Identifying two tags that share some attribute names and values From: Zack Brown <zbrown@xxxxxxxxxxxxxxx> Date: Sun, 5 May 2002 22:03:47 -0700 |
Hi, There's still a problem. when this recipe compares attributes, it sees line-breaks within an attribute and uses them in its comparison. So <a x="hi there"/> won't match <b x="hi there"/>. Is there any way around this? On Sun, May 05, 2002 at 10:08:50AM -0700, Zack Brown wrote: > OUCH! > > I apologize for this, but it looks like I slightly misstated the problem. I > tested your solution and it looks like exactly what I'm looking for, with one > difference: it is not <a> that contains the superset of attributes, with <b> > containing a subset. It's actually <b> that contains the superset, and <a> > contains the subset. > > This variation seems to work for me: > > <xsl:variable name="file2" select="document('2.xml')/outsidedata"/> > <xsl:template match="a"> > <xsl:variable name="a" select="." /> > <xsl:for-each select="$file2/b[@* = $a/@*]"> > <xsl:variable name="b" select="." /> > <xsl:variable name="test"> > <xsl:for-each select="$a/@*"> > <xsl:if test="not($b/@*[name() = name(current())] = .)"> > no attribute with the same name on element b whose value equals this one > </xsl:if> > </xsl:for-each> > </xsl:variable> > <xsl:if test="not(string($test))"> > [<xsl:value-of select="."/>] > </xsl:if> > </xsl:for-each> > </xsl:template> > > Thanks!! > > Zack > > On Sun, May 05, 2002 at 11:01:25AM +0100, Jeni Tennison wrote: > > Hi Zack, > > > > >> I didn't get it with one expression and need the step with $test: > > >> > > >> <xsl:variable name="file1" select="/"/> > > >> <xsl:variable name="file2" select="document('2.xml')/outsidedata"/> > > >> > > >> <xsl:template match="/"> > > >> <xsl:apply-templates select="$file2/b"/> > > > > > > That's a problem, because 2.xml may contain thousands of entries, > > > and I don't want to process each one. I just want to process the <a> > > > from 1.xml and find any corresponding <b> in 2.xml. > > > > To search for a b element in 2.xml that matches your criteria, you're > > going to have to process each of them in some way. I agree that's > > going to be time-consuming given you have thousands of entries. There > > are things that you could do to make it easier to search 2.xml -- > > rearrange the XML so that the bs are grouped by which attributes they > > have, for example. Or carry out some filtering on 2.xml prior to using > > it with XSLT. > > > > If you prefer to think of it as processing the a element, then have a > > template that matches the a element, then you could do so: > > > > <xsl:template match="a"> > > <xsl:variable name="a" select="." /> > > <xsl:for-each select="$file2/b[@* = $a/@*]"> > > <xsl:variable name="test"> > > <xsl:for-each select="@*"> > > <xsl:if test="not($a/@*[name() = name(current())] = .)"> > > no attribute with the same name on element a whose value > > equals this one > > </xsl:if> > > </xsl:for-each> > > </xsl:variable> > > <xsl:if test="not(string($test))"> > > <xsl:text />[<xsl:value-of select="." />]<xsl:text /> > > </xsl:if> > > </xsl:for-each> > > </xsl:template> > > > > Three minor variations on Joerg's solution here. First, I filter the b > > elements that you iterate over to only those that have an attribute > > whose value matches one of the attributes on a. That's just a rough > > filter, and it won't lower the number of visits to b elements overall, > > but it will prevent you from building up the $test variable for every > > one of them. > > > > Second, the test in the middle is a bit simpler. Joerg used: > > > > $file1/a/@*[name()=name(current())][. != current()] or > > not($file1/a/@*[name()=name(current())]) > > > > which returns true if there is an attribute on a with the same name as > > the attribute on b that you're looking at whose value is not equal to > > the attribute on b *or* there's no attribute on a with the same name > > as the attribute on b that you're looking at. > > > > The one I've used above is: > > > > not($a/@*[name() = name(current())] = .) > > > > which returns true if it is not the case that there is an attribute on > > a, with the same name as the attribute on b that you're looking at, > > whose value is the same as the attribute on b. This will therefore > > return true either if the attribute on a with the same name isn't > > equal to the value of the attribute on b, or if there's no attribute > > on a with the same name. > > > > The second slight difference is in the value created for the $test > > variable. All that you need to test here is whether $test ends up > > having some content or not -- the only way it can have content is if > > the test were true for one of the attributes, so you can use > > test="not(string($test))" (does the $test variable not have a string > > value?). Because of this, I tend to use something meaningful as the > > string within the test -- here "no attribute with the same name on > > element a whose value equals this one" because it documents what > > you're doing a little and is helpful if you had to debug the code -- > > you could print out the value of $test and get a meaningful message. > > > > Cheers, > > > > Jeni > > > > --- > > Jeni Tennison > > http://www.jenitennison.com/ > > > > > > XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list > > > > -- > Zack Brown > > XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list > -- Zack Brown XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Re: [xsl] Identifying two tags that, Jeni Tennison | Thread | Re: [xsl] Identifying two tags that, Jeni Tennison |
[xsl] Re: your mail, Zack Brown | Date | RE: [xsl] Sorting XML with XSL, out, Ernst Wolthaus |
Month |