Q:

XSL: Comparing nodes by comparing their child nodes

I would like to be able to compare two nodes based on the values of their child nodes. Testing node equality with the = operator just compares the string values of the respective nodes. I would like to compare them based on values in their child nodes.
To be a bit more specific, I would like <a> and <b> (below) to be equal, because the values of @id are the same for <c> elements that have matching @type attributes also have matching @id attributes.
<a>
    <c type="type-one" id="5675"/>
    <c type="type-two" id="3423"/>
    <c type="type-three" id="9088"/>
</a>
<b>
    <c type="type-one" id="5675"/>
    <c type="type-two" id="3423"/>
</b>

But these would be different:
<a>
    <c type="type-one" id="5675"/>
</a>
<b>
    <c type="type-one" id="2342"/>
</b>

The only solution I can begin to see involves a laborious comparison with a for-each statement, which I would like to avoid if possible.
If possible I would like to stick with XSLT 1.0. I am using xsltproc.

A:

First of all, the relation called "equals" cannot have that name. 
"Equals" means that the relation is an equivalence relation. By definition any equivalence relation ~ must be:

Reflexive: x ~ x .
Symmetric: if x ~ y then y ~ x
Transitive: if x ~ y and y ~ z then x ~ z .

Here is an example, showing that the proposed "equals" relation isn't transitive:
x is:
<a>
    <c type="type-one" id="5675"/>
    <c type="type-two" id="3423"/>
    <c type="type-three" id="9088"/>
</a>

y is:
<b>
    <c type="type-one" id="5675"/>
    <c type="type-two" id="3423"/>
    <c type="type-four" id="1234"/>
</b>

z is:
<b>
    <c type="type-three" id="3333"/>
    <c type="type-four" id="1234"/>
</b>

Now, we can see that x ~ y and y ~ z. However, clearly this doesn't hold: x ~ z
This said, I am calling the relation "matches" and it is relaxed and not "equals".
Here is a solution to the problem, with the above adjustment:
Do note that this cannot be expressed with a single XPath expression, because XPath 1.0 (used within an XSLT 1.0 transformation) doesn't have range variables.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="/*">
     <xsl:call-template name="matches">
       <xsl:with-param name="pElem1" select="a"/>
       <xsl:with-param name="pElem2" select="b"/>
     </xsl:call-template>
 </xsl:template>

 <xsl:template name="matches">
   <xsl:param name="pElem1" select="/.."/>
   <xsl:param name="pElem2" select="/.."/>

   <xsl:variable name="vMisMatch">
       <xsl:for-each select="$pElem1/c[@type = $pElem2/c/@type]">
        <xsl:if test=
           "$pElem2/c[@type = current()/@type and not(@id = current()/@id)]">1</xsl:if>
       </xsl:for-each>
   </xsl:variable>

   <xsl:copy-of select="not(string($vMisMatch))"/>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the following XML document:
<t>
    <a>
        <c type="type-one" id="5675"/>
        <c type="type-two" id="3423"/>
        <c type="type-three" id="9088"/>
    </a>
    <b>
        <c type="type-one" id="5675"/>
        <c type="type-two" id="3423"/>
    </b>
</t>

the wanted, correct result is produced:
true

When the same transformation is applied on this XML document:
<t>
    <a>
        <c type="type-one" id="5675"/>
        <c type="type-two" id="3423"/>
        <c type="type-three" id="9088"/>
    </a>
    <b>
        <c type="type-one" id="5675"/>
        <c type="type-two" id="9876"/>
    </b>
</t>

again the correct result is produced:
false

