This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
Selecting across documents with composite keys
- To: XSL List <xsl-list at lists dot mulberrytech dot com>
- Subject: [xsl] Selecting across documents with composite keys
- From: Joerg Pietschmann <joerg dot pietschmann at zkb dot ch>
- Date: Thu, 09 Aug 2001 11:04:22 +0200
- Organization: ZKB
- Reply-To: xsl-list at lists dot mulberrytech dot com
Hello All,
i have two documents with the same structure, roughly
<!ELEMENT root (e+)>
<!ELEMENT e (name1,name2,stuff)>
The documents are pulled into the processur using document().
I want to select all elements from the first document for
which there are elements in the second document having both
the same content in name1 and name2.
Some non-starters:
If the key were only the name1 child element, i could use
select="$doc1/root/e[name1=$doc2/root/e/name1]"
If it were in the same document, i could use key():
<xsl:key name="e" match="e" use="concat(name1,':',name2)"/>
...
select="$doc1[count(key('e',concat(name1,':',name2))>1]"
(or something)
Doing
select="$doc1/root/e[name1=$doc2/root/e/name1
and name2=$doc2/root/e/name2]"
is obviously wrong. Counterexample:
Doc1
<root>
<e><name1>A</name1><name2>B</name2></e>
</root>
Doc2
<root>
<e><name1>A</name1><name2>C</name2></e>
<e><name1>D</name1><name2>B</name2></e>
</root>
Currently i use a recursive template to gather the desired elements:
<xsl:variable name="doc1" select="document('xml1')"/>
<xsl:variable name="doc2" select="document('xml2')"/>
<xsl:key name="e" match="e" use="concat(name1,':',name2)"/>
<xsl:template name="gather-common-elements">
<xsl:param name="result"/>
<xsl:param name="todo"/>
<xsl:choose>
<xsl:when test="$todo">
<xsl:variable name="key" select="concat($todo[1]/name1,':',todo[1]/name2)"/>
<xsl:call-template name="gather-common-elements">
<xsl:with-param name="result" select="$result|$todo[1][doc2[key('e',$key)]"/>
<xsl:with-param name="todo" select="$todo[position()>1]"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<!-- processing $result here -->
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="/">
<xsl:call-template name="gather-common-elements">
<xsl:with-param name="result" select="/.."/>
<xsl:with-param name="todo" select="$doc1/root/e"/>
</xsl:call-template>
</xsl:template>
I'd like to have the desired elements in a variable because the set is
processed multiple times in complicated ways, doing a for-each on
$doc1/root/e for each step and checking each time the presence in $doc2
has proved to be *much* slower than the recursive template solution
above.
Any other ideas? A beer for a working one-line XPath expression! (this excludes
using xx:node-set, as usual :-)
Regards
J.Pietschmann
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list