My input xml is as under
<ns0:ProjectSync xmlns:ns0="http://XSLMapTesting.ProjectSync">
<Funder>
<OID>1</OID>
<FFC>FFC1</FFC>
</Funder>
<Funder>
<OID>2</OID>
<FFC></FFC>
</Funder>
<Funder>
<OID>3</OID>
<FFC>FFC3</FFC>
</Funder>
<Funder>
<OID>4</OID>
<FFC></FFC>
</Funder>
<ActiveBudget>
<BudgetLines>
<Fund>
<ID>1</ID>
</Fund>
</BudgetLines>
<BudgetLines>
<Fund>
<ID>4</ID>
</Fund>
</BudgetLines>
</ActiveBudget>
</ns0:ProjectSync>
My mapping xslt code is as under
<xsl:template match="/">
<xsl:apply-templates select="/s0:ProjectSync" />
</xsl:template>
<!--
////////////////////////////////////////
ProjectSync template
////////////////////////////////////////
-->
<xsl:template match="/s0:ProjectSync">
<ns0:Projects>
<Project>
<Funders>
<xsl:apply-templates select="Funder[*]" />
</Funders>
<Budgets>
<xsl:apply-templates select="ActiveBudget/BudgetLines[*]" />
</Budgets>
</Project>
</ns0:Projects>
</xsl:template>
<!--
////////////////////////////////////////
Funders template
////////////////////////////////////////
-->
<xsl:template match="Funder">
<Funder>
<ID>
<xsl:choose>
<xsl:when test="FFC != ''">
<xsl:value-of select="FFC/text()"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="OID/text()" />
</xsl:otherwise>
</xsl:choose>
</ID>
</Funder>
</xsl:template>
<!--
////////////////////////////////////////
BudgetLines template
////////////////////////////////////////
-->
<xsl:template match="ActiveBudget/BudgetLines">
<BudgetLine>
<FundID>
<xsl:value-of select="Fund/ID/text()" />
</FundID>
</BudgetLine>
</xsl:template>
</xsl:stylesheet>
In the "BudgetLines template" above I want to apply a logic like for each budgetline it iterates through the Funders recordset and see if it finds a funder with same ID and also has a FFC populated, then FFC should be mapped. otherwise, Fund/ID should be mapped in the output xml. The same logic is also defined in the following code:
for-each select="BudgetLine"
for-each select="Funder"
choose
when test="BudgetLine/Fund/ID = Funder/OID & Funder/FFC != ''"
<xsl:value-of select="Funder/FFC/text()" />
break;
otherwise
<xsl:value-of select="BudgetLine/Fund/ID/text()" />
The expected output for the above xml should be as under
<ns0:Projects xmlns:ns0="http://XSLMapTesting.Projects">
<Project>
<Funders>
<Funder>
<ID>FFC1</ID>
</Funder>
<Funder>
<ID>2</ID>
</Funder>
<Funder>
<ID>FFC3</ID>
</Funder>
<Funder>
<ID>4</ID>
</Funder>
</Funders>
<Budgets>
<BudgetLine>
<FundID>FFC1</FundID>
</BudgetLine>
<BudgetLine>
<FundID>4</FundID>
</BudgetLine>
</Budgets>
</Project>
</ns0:Projects>
how can I achieve this in xsl please? Thank you
If I understand your requirements correctly, I would suggest you do something like:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="funder" match="Funder" use="OID" />
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Funder">
<xsl:copy>
<ID>
<xsl:choose>
<xsl:when test="FFC/text()">
<xsl:value-of select="FFC"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="OID"/>
</xsl:otherwise>
</xsl:choose>
</ID>
</xsl:copy>
</xsl:template>
<xsl:template match="ActiveBudget">
<Budgets>
<xsl:apply-templates/>
</Budgets>
</xsl:template>
<xsl:template match="BudgetLines">
<xsl:variable name="funder" select="key('funder', Fund/ID)" />
<BudgetLine>
<FundID>
<xsl:choose>
<xsl:when test="$funder/FFC/text()">
<xsl:value-of select="$funder/FFC"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$funder/OID"/>
</xsl:otherwise>
</xsl:choose>
</FundID>
</BudgetLine>
</xsl:template>
</xsl:stylesheet>
The code could be compacted somewhat if your processor supports XSLT 2.0 or higher.
(Added)
Actually, even in XSLT 1.0 you could reduce:
<xsl:choose>
<xsl:when test="FFC/text()">
<xsl:value-of select="FFC"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="OID"/>
</xsl:otherwise>
</xsl:choose>
to:
<xsl:value-of select="(OID | FFC/text())[last()]"/>
and likewise for the other xsl:choose
instruction.