+1 for Dirk's suggestion to use XSLT 2.0 and for-each-group.
I poked around with XQuery to do this also...my hack isn't going to be as efficient as it should because it pulls the doc into memory twice. I need to look in to the union functionality for XQuery to improve it, but given this:
<ead xmlns="http://loc.gov/ead">
<c0x>
<unittitle>Horse, still life</unittitle>
<origination>Picasso</origination>
</c0x>
<c0x>
<unittitle>Apple, still life</unittitle>
<origination>Picasso</origination>
</c0x>
<c0x>
<unittitle>Giraffe, still life</unittitle>
<origination>Holbein</origination>
</c0x>
<c0x>
<unittitle>Baby, still life</unittitle>
<origination>Fra Angelico</origination>
</c0x>
<c0x>
<unittitle>Frog, still life</unittitle>
<origination>Michelangelo</origination>
</c0x>
<c0x>
<unittitle>Elephant, still life</unittitle>
<origination>Holbein</origination>
</c0x>
<c0x>
<unittitle>Chair, still life</unittitle>
<origination>Picasso</origination>
</c0x>
<c0x>
<unittitle>Duck, still life</unittitle>
<origination>Michelangelo</origination>
</c0x>
</ead>
you can use the following to get somewhat close to what you needed.
xquery version "1.0";
declare namespace m = "http://monarchos.com";
declare namespace ead = "http://loc.gov/ead";
declare function m:orig($name) {
let $originator := $name
let $query :=
for $lmnop in doc('/db/ead/ead.xml')/ead:ead/ead:c0x/ead:origination[text() eq $originator]
order by $lmnop/preceding-sibling::ead:unittitle ascending
return string($lmnop/preceding-sibling::ead:unittitle)
return $query
};
<dl xmlns="http://www.w3.org/1999/xhtml"> {
let $orig := for $lmnop in doc('/db/ead/ead.xml')/ead:ead return distinct-values($lmnop/ead:c0x/ead:origination)
let $titles :=
for $name in $orig
order by $name ascending
return (<dt>{$name}</dt>, <dd>{m:orig($name)}</dd>)
return $titles
}
</dl>
>>> Dirk van Laanen <[log in to unmask]> 02/08/08 4:03 AM >>>
supposing
<c01><did>
<unittitle>Duck, still life</unittitle>
<origination>Michelangelo</origination>
</did></c01>
In XSLT 2.0 you might use
<xsl:for-each-group select="/ead/archdesc/dsc/c01/did" group-by="origination">
<xsl:sort select="current-grouping-key()"/>
<xsl:text>
</xsl:text>
<xsl:value-of select="origination" />
<xsl:for-each-group select="current-group()" group-by=".">
<xsl:sort select="unittitle"/>
<xsl:text>
</xsl:text>
<xsl:value-of select="unittitle" />
</xsl:for-each-group>
</xsl:for-each-group>
<xsl:text>
</xsl:text>
Not very hip on me keys, but in XSLT 1.0 you might try Muenchian grouping.
<xsl:key name="painter" match="did" use="origination" />
<xsl:template match="/">
<xsl:text>
</xsl:text>
<xsl:for-each select="/ead/archdesc/dsc/c01/did[generate-id(.) =
generate-id(key('painter', origination)[1])]">
<xsl:sort select="origination"/>
<xsl:value-of select="origination" />
<xsl:for-each select="key('painter', origination)">
<xsl:sort select="unittitle"/>
<xsl:text>
</xsl:text>
<xsl:value-of select="unittitle" />
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:template>
Regards, Dirk
|