This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
Re: How to remove duplicates nodes?
- To: Joel Riedesel <jriedese at jnana dot com>
- Subject: Re: How to remove duplicates nodes?
- From: Jeni Tennison <mail at jenitennison dot com>
- Date: Sat, 26 Aug 2000 09:29:05 +0100
- Cc: xsl-list at mulberrytech dot com
- References: <85256946.00732A0C.00@cch_lis_smtp.cch-lis.com>
- Reply-To: xsl-list at mulberrytech dot com
Joel,
>I don't believe I can use the 'key' trick since the Context element
>is throughout my XML and I only want to do this duplicate analysis
>from within a particular rule mapping element.
This does add an extra factor into using the Muenchian Method for getting
unique nodes. [This email assumes familiarity with the general method -
look at http://www.jenitennison.com/xslt/grouping/ for more details.]
There are two ways that you can do it.
The first is to declare the key in the normal way: you're interested in
Context elements, and the unique thing about the Context element is (I
think?) the @objectID of the ObjectReference that it holds:
<xsl:key name="contexts" match="Context" use="ObjectReference/@objectID" />
This means that with key('contexts', $objectID) you will get all the
Contexts in the source that have that particular ObjectReference/@objectID.
If you know what RuleMapping you're interested in, you can filter those
nodes in terms of that RuleMapping. So, within a template matching
RuleMapping elements, if you set a variable to hold the id of the RuleMapping:
<xsl:variable name="rule-mapping" select="@id" />
You can then filter the Contexts returned by the key (using a predicate) to
give only those Contexts that have that RuleMapping as an ancestor:
key('contexts', $objectID)[ancestor::RuleMapping[@id = $rule-mapping]]
So this XPath will give all the Contexts within that particular RuleMapping
that have that particular ObjectReference/@objectID. Slotting that in to
the usual Muenchian solution, you get:
<xsl:template match="RuleMapping">
<xsl:variable name="rule-mapping" select="@id" />
Rule Mapping: <xsl:value-of select="@name" />
Unique Contexts:
<xsl:copy-of
select="Rule/RHS/Context[generate-id() = generate-id(key('contexts',
ObjectReference/@objectID)[ancestor::RuleMapping[@id =
$rule-mapping]][1])]" />
</xsl:template>
Filtering the results of the key() function to get only those returned by
it that meet a certain criteria, is a good general solution. It's
especially useful when you want a dynamic way of filtering the results of
the key, such as a keyword passed in as a parameter.
The second method, which may be better in your case, is to create a key
with key values that hold information both about the
ObjectReference/@objectID *and* about the RuleMapping that the Context is
within. You can do this by concatenating the two pieces of information
(with an appropriate separator) to give the key value:
<xsl:key name="contexts" match="Context"
use="concat(ancestor::RuleMapping/@id, '::', ObjectReference/@objectID)" />
You can then index into the key using a value constructed in the same way,
giving the template:
<xsl:template match="RuleMapping">
<xsl:variable name="rule-mapping" select="@id" />
Rule Mapping: <xsl:value-of select="@name" />
Unique Contexts:
<xsl:copy-of
select="Rule/RHS/Context[generate-id() = generate-id(key('contexts',
concat($rule-mapping, '::', ObjectReference/@objectID))[1])]" />
</xsl:template>
Both of these methods give the results that you're after in both SAXON and
Xalan.
I hope that this helps,
Jeni
Jeni Tennison
http://www.jenitennison.com/
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list