I'm new in this XSLT-thing and I can't figure out how to this:
This is a snippet from the xml i start with:
<Article>
<Bullettext>10,00 </Bullettext>
<Bullettext>8,00 </Bullettext>
</Article>
<Article>
<something>some text</something>
</Article>
<Article>
<Corpsdetexte>Bulgaria</Corpsdetexte>
<Bullettext>15,0 </Bullettext>
<Bullettext>10,0 </Bullettext>
</Article> `
This is what i want the output to be:
<LIST>
<ITEM>12,00 </ITEM>
<ITEM>10,00 </ITEM>
<ITEM>8,00 </ITEM>
</LIST>
<P>
<something>some text</something>
</P>
<P>
<Corpsdetexte>Bulgaria</Corpsdetexte>
</P>
<LIST>
<ITEM>15,0 </ITEM>
<ITEM>10,0 </ITEM>
</LIST>
Any ideas??
I think you're looking for a conditional deep-copy.
Here's the code in the link above rewritten for your situation:
The input I used was:
And it gave me:
It's a bit messy if you want to do the other transformations like adding
<p></p>
s in the same stylesheet but if you do a two step transformation with two stylesheets, the first doing the conditional deep copy above and then the second doing your main transformation using the result of the first, you should be good to go.From your comment in response to Rubens Farias's answer (and really, that's something you should edit your question to include), it seems that you want a generic way to transform any group of adjacent
BulletText
elements into a list. That gets us to two questions: how do we find such groups, and having found them, how do we transform them into a list?To find a group, we need to look for all
BulletText
elements whose immediately preceding sibling isn't aBulletText
element. Each one of those starts a group, and those are the elements that we're going to transform into lists. So the first thing we want to do is create an XPath expression that will find them:If you look at the predicates in that XPath expression, it's doing just what I said we need to do: it matches a
BulletText
element if it's not the case that its first preceding sibling (preceding-sibling::*[1]
) has a name ofBulletText
. Note that if the element has no preceding sibling, this expression will still match it.So now we can create a template that matches these start-of-group elements. What do we put inside this template? We're going to transform these elements into
LIST
elements, so the template's going to start out looking like:Easy enough. But how do we find the elements that are going to populate that list? There are two cases we have to deal with.
The first is simple: if all of the following siblings are
BulletText
elements, we want to populate the list with this element and all of its following siblings.The second is harder. If there's a following sibling that's not a
BulletText
element, we want our list to be all of the children of the current element's parent, starting at the current element and ending before the stop element. Here is a case where we need to use thecount()
function to calculate the starting and ending indexes, and theposition()
function to find the position of each element.The completed template looks like this:
You need two other templates. One converts
BulletText
elements into items - we usemode
here so that we can apply it toBulletText
elements without invoking the template we're currently using:Then you also need a template that keeps
BulletText
elements that our first template doesn't match from generating any output (because if we're using the identity transform, they'll just get copied if we don't):Because of the magic of XSLT's template precedence rules, any
BulletText
element that both templates match will be transformed by the first one, and this one will catch the rest.Just add those three templates to the identity transform and you're good to go.
Grouping Siblings with Three Templates
Although there are currently several working answers to this question, you can actually group siblings very easily with three templates and the identity.
First, you need a template that will just remove all of the nodes and set its priority, so that we can override it with another template.
Then, define a template that matches any node that is not preceded by itself, assigning it a higher priority. This template will inject the group and then start copying nodes in a different mode.
Finally, define a tail recursive template to deal with the items being grouped.
Here is a complete stylesheet that will group the Bullettext elements in the example:
Try something like this: