This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
Re: Identifying two tags that share some attribute names and values
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