Reputation: 15
I have the below input xml where some mandatory xml tags are missing like <email_template_id> which needs to be reproduced in the output in the same sequence
<?xml version="1.0" encoding="UTF-8"?>
<rsp stat="ok" version="1.0">
<result>
<total_results>700</total_results>
<emailClick>
<id>1</id>
<url>https://www.google.com</url>
<email_template_id>12</email_template_id>
<created_at>2023-02-14 00:00:10</created_at>
</emailClick>
<emailClick>
<id>2</id>
<url>https://www.hello.com</url>
<created_at>2023-02-14 00:00:10</created_at>
</emailClick>
</result>
</rsp>
and need the below output
<emailClick>
<id>1</id>
<url>https://www.google.com</url>
<email_template_id>12</email_template_id>
<created_at>2023-02-14 00:00:10</created_at>
</emailClick>
<emailClick>
<id>2</id>
<url>https://www.hello.com</url>
<email_template_id/>
<created_at>2023-02-14 00:00:10</created_at>
</emailClick>
I am using below xslt to achieve this output
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" omit-xml-declaration="yes" indent ="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:for-each select="rsp/result/emailClick">
<emailClick>
<id><xsl:value-of select="id" /></id>
<url><xsl:value-of select="url" /></url>
<email_template_id><xsl:value-of select="email_template_id"/></email_template_id>
<created_at><xsl:value-of select="created_at"/></created_at>
</emailClick>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Is there any better way to achieve this , any guidance would be highly appreciated
Upvotes: 0
Views: 120
Reputation: 1235
This is a push programming approach. Which means it pushes the child nodes using apply-templates. It also uses a mode. So the nodes being output are pushed to an identity template.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" omit-xml-declaration="yes" indent ="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()">
<xsl:apply-templates select="node()"/>
</xsl:template>
<xsl:template match="emailClick">
<xsl:copy>
<xsl:apply-templates select="@*" mode="output"/>
<xsl:choose>
<xsl:when test="id">
<xsl:apply-templates select="id" mode="output"/>
</xsl:when>
<xsl:otherwise>
<xsl:element name="id"/>
</xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="url">
<xsl:apply-templates select="url" mode="output"/>
</xsl:when>
<xsl:otherwise>
<xsl:element name="url"/>
</xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="email_template_id">
<xsl:apply-templates select="email_template_id" mode="output"/>
</xsl:when>
<xsl:otherwise>
<xsl:element name="email_template_id"/>
</xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="created_at">
<xsl:apply-templates select="created_at" mode="output"/>
</xsl:when>
<xsl:otherwise>
<xsl:element name="created_at"/>
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>
<!-- Identity. -->
<xsl:template match="node()|@*" mode="output">
<xsl:copy>
<xsl:apply-templates select="node()|@*" mode="output"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0
Reputation: 17507
The following stylesheet avoids any mention of element names inside the xsl:for-each
and instead reads the mandatory element names from the <so:emailClick>
element and processes them generically:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:so="https://stackoverflow.com">
<xsl:output method="xml" encoding="utf-8" omit-xml-declaration="yes" indent="yes" />
<xsl:strip-space elements="*" />
<so:emailClick>
<id />
<url />
<email_template_id />
<created_at />
</so:emailClick>
<xsl:template match="/">
<xsl:for-each select="rsp/result/emailClick">
<xsl:variable name="this" select="." />
<xsl:copy>
<xsl:for-each select="document('')/*/so:*[local-name()=name(current())]/*">
<xsl:element name="{name()}">
<xsl:value-of select="$this/*[name()=name(current())]" />
</xsl:element>
</xsl:for-each>
</xsl:copy>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Is that what you meant by "a generic way of doing this"?
(XSLT 1.0)
Upvotes: 0