Transform attribute to element when element already has a value

Here should go questions about transforming XML with XSLT and FOP.
Fiona Chen
Posts: 17
Joined: Fri Aug 21, 2020 5:40 pm

Transform attribute to element when element already has a value

Post by Fiona Chen » Wed May 19, 2021 9:29 pm

Hello, I need some help to transform below XML:

Code: Select all

<requestConfirmation xmlns="http://example/confirmation">
    <trade>
        <cal>
            <c>PRECEDING</c>
            <bcs id="businessCenters">
                <bc>USNY</bc>
                <bc>GBLO</bc>
            </bcs>
        </cal>  
        <amount>
            <currency id="settlementCurrency" currencyScheme="http://example/iso4">USD</currency>
            <referenceAmount>StandardISDA</referenceAmount>
            <cashSettlement>true</cashSettlement>
        </amount>
    </trade>
</requestConfirmation>
The desired result:

Code: Select all

<requestProduct xmlns="http://fc.fasset/product">
   <trade>
      <cal>
         <c>PRECEDING</c>
         <bcs>
            <id>businessCenters</id>
            <bc>USNY</bc>
            <bc>GBLO</bc>
         </bcs>
      </cal>
      <amount>
         <currency>USD</currency>
         <id>settlementCurrency</id>
         <referenceAmount>StandardISDA</referenceAmount>
         <cashSettlement>true</cashSettlement>
      </amount>
   </trade>
</requestProduct>
There are three criteria for the transformation:
1) new namespace
2) new root element
3) targeted transformed Attribute(s)

My XSLT module is:

Code: Select all

   
    <xsl:param name="namespace" as="xs:string">http://fc.fasset/product</xsl:param>
    <xsl:param name="root" as="xs:string">requestProduct</xsl:param>
    <xsl:param name="keepAttr" static="yes" as="xs:string*" select="'href', 'id'"/>
    
    <xsl:template match="/*">
        <xsl:element name="{$root}" namespace="{$namespace}">
            <xsl:apply-templates select="@* , node()"/>
        </xsl:element>
    </xsl:template>
    
    <xsl:template match="*">
        <xsl:element name="{local-name()}" namespace="{$namespace}">
            <xsl:apply-templates select="@* , node()"/>
        </xsl:element>
    </xsl:template>
    
    <xsl:template match="@*">
        <xsl:choose>
            <xsl:when test="local-name() = $keepAttr">
                <xsl:element name="{local-name()}" namespace="{$namespace}">
                    <xsl:value-of select="."/>
                </xsl:element>
            </xsl:when>
        </xsl:choose>
    </xsl:template>
But the result is undesirable when the original element (in this case, it is the <currency> element) already has a value: USD.
My module produces unintended result:

Code: Select all

<requestProduct xmlns="http://fc.fasset/product">
   <trade>
      <cal>
         <c>PRECEDING</c>
         <bcs>
            <id>businessCenters</id>
            <bc>USNY</bc>
            <bc>GBLO</bc>
         </bcs>
      </cal>
      <amount>
         <currency>
            <id>settlementCurrency</id>USD</currency>
         <referenceAmount>StandardISDA</referenceAmount>
         <cashSettlement>true</cashSettlement>
      </amount>
   </trade>
</requestProduct>
What is the solution to fix the problem?

tavy
Posts: 284
Joined: Thu Jul 01, 2004 12:29 pm

Re: Transform attribute to element when element already has a value

Post by tavy » Thu May 20, 2021 2:43 pm

Hello,

Probably you can add a template special for the "currency" element, something like this:

Code: Select all

<xsl:param name="namespace" as="xs:string">http://fc.fasset/product</xsl:param>
<xsl:param name="root" as="xs:string">requestProduct</xsl:param>
<xsl:param name="keepAttr" static="yes" as="xs:string*" select="'href', 'id'"/>

<xsl:template match="/*">
    <xsl:element name="{$root}" namespace="{$namespace}">
        <xsl:apply-templates select="@* , node()"/>
    </xsl:element>
</xsl:template>

<xsl:template match="*:currency">
    <xsl:element name="{local-name()}" namespace="{$namespace}">
        <xsl:value-of select="text()"/>
    </xsl:element>
    <xsl:apply-templates select="@*"/>
</xsl:template>

<xsl:template match="*">
    <xsl:element name="{local-name()}" namespace="{$namespace}">
        <xsl:apply-templates select="@* , node()"/>
    </xsl:element>
</xsl:template>

<xsl:template match="@*">
    <xsl:choose>
        <xsl:when test="local-name() = $keepAttr">
            <xsl:element name="{local-name()}" namespace="{$namespace}">
                <xsl:value-of select="."/>
            </xsl:element>
        </xsl:when>
    </xsl:choose>
</xsl:template>
Maybe you can try to ask this question on the XSLT list (xsl-list@lists.mulberrytech.com), there are more XSLT users to respond there.

Best Regards,
Octavian
Octavian Nadolu
<oXygen/> XML Editor
http://www.oxygenxml.com

Fiona Chen
Posts: 17
Joined: Fri Aug 21, 2020 5:40 pm

Re: Transform attribute to element when element already has a value

Post by Fiona Chen » Sun May 23, 2021 12:33 am

Thank you, Octavian! This is very helpful!

Post Reply