I need to transform an XML file with XSLT, and this task is kinda tricky.
I have attributes with the name attr_1000_a whereas the number and the suffix are dynamic, so that attr_2000_b is valid too.
Further, there are <row> elements which combine related data. I need to transform them so that equally numbered attributes (i.e. attr_1000_a and attr_1000_b) are put into the same element.
Let me give you an example. Following input XML:
<root>
<row id="1">
<foo attr_1000_a="true">1</foo>
<foo attr_1000_b="true">2</foo>
<foo attr_1000_c="true">3</foo>
</row>
<row id="2">
<foo attr_1000_a="true" attr_1000_b="true" attr_1000_c="true">10</foo>
<foo attr_2000_a="true" attr_2000_b="true" attr_2000_c="true">20</foo>
</row>
<row id="3">
<foo attr_1000_a="true" attr_2000_a="true" attr_3000_a="true">100</foo>
<foo attr_1000_b="true" attr_2000_b="true" attr_3000_b="true">200</foo>
<foo attr_1000_c="true" attr_2000_c="true" attr_3000_c="true">300</foo>
</row>
</root>
You can see that the attributes can be combined in several ways, which makes the transformation difficult. Each attribute is unique in each <row> but can be located in any <foo> element. Also, each <foo> can have an arbitrary number of attributes.
The desired result:
<result>
<row id="1">
<field attr="1000">
<a>1</a>
<b>2</b>
<c>3</c>
</field>
</row>
<row id="2">
<field attr="1000">
<a>10</a>
<b>10</b>
<c>10</c>
</field>
<field attr="2000">
<a>20</a>
<b>20</b>
<c>20</c>
</field>
</row>
<row id="3">
<field attr="1000">
<a>100</a>
<b>200</b>
<c>300</c>
</field>
<field attr="2000">
<a>100</a>
<b>200</b>
<c>300</c>
</field>
<field attr="3000">
<a>100</a>
<b>200</b>
<c>300</c>
</field>
</row>
</result>
I think i have to somehow get a list of all numbers in a row (for example 1000, 2000 and 3000) and then iterate through all elements that have such an attriute.
How can i do this using XSLT? Is this even possible?
Quick and Dirty, this xslt
applied to this input
yields this result
the magic is in
this creates the a/b/c elements with a dynamic name and travels up one node to get the value from the parent node (we’re currently in the attribute).
and in
which regroups all attributes (
foo/@*) using part of their name (substring(local-name(),1,9)). The first are subsequently available ascurrent-group(), the latter ascurrent-grouping-key(), as you can see.