XSLT combine multiple Parents
I’m new to XSLT. I’m trying to create an XSLT
Here’s the XML Code
<?xml version="1.0" encoding="utf-8"?> <?xml-stylesheet href="orders.xslt" type="text/xsl"?> <report> <orders> <order> <order_id>123</order_id> <order_name>Doritos</order_name> </order> <order> <order_id>234</order_id> <order_name>Pringles</order_name> </order> </orders> <order_actions> <order_action> <order_id>123</order_id> <order_action_dt>27-06-2020 07.00</order_action_dt> <action_name>ordered</action_name> </order_action> <order_action> <order_id>123</order_id> <order_action_dt>27-06-2020 09.00</order_action_dt> <action_name>dispatched</action_name> </order_action> <order_action> <order_id>123</order_id> <order_action_dt>27-06-2020 15.00</order_action_dt> <action_name>delivered</action_name> </order_action> <order_action> <order_id>234</order_id> <order_action_dt>27-06-2020 07.30</order_action_dt> <action_name>ordered</action_name> </order_action> <order_action> <order_id>234</order_id> <order_action_dt>27-06-2020 09.50</order_action_dt> <action_name>dispatched</action_name> </order_action> </order_actions> </report> <!-- language: lang-xml --> Here's my XSLT Code
What I would like to do is Group them Like below but not sure how.
UPDATE: Trying to add the XSLT Code but I’m getting an error
UPDATE 2: After Adding xsl:apply-template inside for-each
<xsl:for-each select="order"> <table border="1"> <tr> <td> ORDER_ID </td> <td> <xsl:value-of select="order_id"/> </td> <td> ORDER_NAME </td> <td> <xsl:value-of select="order_name"/> </td> </tr> <xsl:apply-templates select="/report/order_actions/order_action[order_id = ./order_id]" /> </table> </xsl:for-each>
When I add the xsl-template after xsl:apply-templates
<xsl:for-each select="order"> <table border="1"> <tr> <td> ORDER_ID </td> <td> <xsl:value-of select="order_id"/> </td> <td> ORDER_NAME </td> <td> <xsl:value-of select="order_name"/> </td> </tr> <xsl:apply-templates select="/report/order_actions/order_action[order_id = ./order_id]" /> <xsl:template match="order_action" > <tr> </tr> </xsl:template> </table> </xsl:for-each>
UPDATE 3: So I added the xsl:apply-templates like so
<xsl:for-each select="order"> <table border="1"> <tr> <td> ORDER_ID </td> <td> <xsl:value-of select="order_id"/> </td> <td> ORDER_NAME </td> <td> <xsl:value-of select="order_name"/> </td> </tr> <xsl:apply-templates select="/report/order_actions/order_action[order_id = ./order_id]" /> </table> </xsl:for-each>
Then added a new template outside the first template
<xsl:template match="order_action"> <tr xmlns="http://www.w3.org/1999/xhtml"> <td>Order Status</td> <td> <xsl:value-of select="action_name"/> </td> </tr> <tr xmlns="http://www.w3.org/1999/xhtml"> <td>Order Date</td> <td colspan=""> <xsl:value-of select="order_action_dt"/> </td> </tr> </xsl:template>
The problem now is it’s showing all the order_action per order_id
Following your code for the header row, you could achieve this by an
<xsl:apply-templates select="/report/order_actions/order_action[order_id = current()/order_id]" />
As well as a template to create the order action rows:
<xsl:template match="order_action" > <tr> ....your code here </tr> </xsl:template>
The select
on apply-templates
filters the node-set of order_actions to those which match the order by id before invoking the template. The second template runs once per order_action in this node-set.
You may also want to sort them by the date they occurred, assuming they don’t necessarily appear in the document in date order. In which case, add an
<xsl:sort select="order_action_dt" order="descending" />
inside the apply-templates.
edit:
I mistakenly used the shorthand for the context node .
and not the current node current()
– where the context node changes inside an XPath selector because it is evaluating a node-set and each one in turn becomes the context node. The current node is the node currently in scope for the template. Replacing ./order_id
for current()/order_id
should get you what you want.