This is the mail archive of the xsl-list@mulberrytech.com mailing list .


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Selecting across documents with composite keys


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]