In article <ed**************************@posting.google.com >,
Erhard Schwenk <es******@fto.de> wrote:
Maybe this is a faq, if so, point me the URL please.
It's certainly very similar to the question posted here by Marc
Baumgartner (mo***@gmx.de) in June.
input:
<doc>
<a/><a/><b/><a><a><a><b/><a><b/><a><a>
</doc>
output:
<doc>
<section><x/><x/></section>
<section><y/><x/><x/><x/></section>
<section><y/><x/></section>
<section><y/><x/><x/>
</doc>
e.g. I want to transform <a/> to <x/> and <b/> to <y/>, but start a
new section at each <b/>
Here's a general approach to this kind of problem.
Construct an XPath that will identify one member of each group. In
this case, the first <a> is the obvious thing to choose (if there was
always a <b> in the group, the <b> would be a better choice). We can
identify the first <a> in each group as being an <a> whose immediate
preceding-sibling is not an <a>:
a[local-name(preceding-sibling::*[1]) != 'a']
(If there is an <a> at the start without a preceding b, this will
still work because local-name retrns an exmpty string for an empty
node-set.)
Call apply-templates on that path. Use a mode, for reasons that will
be apparent later:
<xsl:template match="doc">
<doc>
<xsl:apply-templates mode="group"
select="a[local-name(preceding-sibling::*[1]) != 'a']"/>
</doc>
</xsl:template>
In the template for the selected representative, output the group
wrapper.
<xsl:template match="a" mode="group">
<section>
...
</section>
</xsl:template>
Now construct an XPath that will select all the elements in the same
group as the representative.
The XPath to select the group members will use something they have in
common with the representative element. Thinking up a test for this
is often the tricky bit. In this case, we want the <b> before the
representative <a> (if there is one) and the <a>s that are following
siblings of the representative <a> without any intervening <b>s. We
can do it by selecting the siblings that have the same number of
following-sibling <b>s as the representative <a>:
../*[count(following-sibling::b) = count(current()/following-sibling::b)]
Note the use of current() to get hold of the representative <a> inside
the predicate. We could have assigned it to a variable instead, but
this is simpler.
Sometimes the obvious test involves comparing two nodes for identity.
For that you can use the trick generate-id(node1) = generate-id(node2).
Inside the wrapper, call apply-templates on the members of the group.
This is why we used a mode for the group template; we are going to
call apply-templates on the representative again in its role as a
member of the group.
<xsl:template match="a" mode="group">
<section>
<xsl:apply-templates select="../*[count(following-sibling::b) =
count(current()/following-sibling::b)]"/>
</section>
</xsl:template>
Now write templates for the group members, which is trivial in this case.
<xsl:template match="a">
<a/>
</xsl:template>
<xsl:template match="b">
<y/>
</xsl:template>
-- Richard
--
Spam filter: to mail me from a .com/.net site, put my surname in the headers.
FreeBSD rules!