Re: [xsl] Identifying two tags that share some attribute names and values

Subject: Re: [xsl] Identifying two tags that share some attribute names and values
From: Zack Brown <zbrown@xxxxxxxxxxxxxxx>
Date: Sun, 5 May 2002 10:08:50 -0700
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


Current Thread