Re: How to remove duplicates nodes?

Subject: Re: How to remove duplicates nodes?
From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx>
Date: Sat, 26 Aug 2000 09:29:05 +0100
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


Current Thread