tags:

views:

29

answers:

1

This is a bit complex and I really don't now if it is possible. I got this XML:

<XML>
<member>
    <InicialAmount>10000000</InitialAmount>
    <Flows>
        <Payment>
            <Date>20100621</Date>
            <Period>
                <Amount>10000000</Amount>
                <StartDate>20100521</StartDate>
                <EndDate>20100621</EndDate>
                <contribution>
                    <contributionFlow>
                        <Amount>10000000</Amount>
                        <StartDate>20100521</StartDate>
                        <EndDate>20100621</EndDate>
                    </contributionFlow>
                </contribution>
            </Period>
        </Payment>
        <Payment>
            <Date>20100823</Date>
            <Period>
                <Amount>9000000</Amount>
                <StartDate>20100621</StartDate>
                <EndDate>20100921</EndDate>
                <contribution>
                    <contributionFlow>
                        <Amount>9000000</Amount>
                        <StartDate>20100621</StartDate>
                        <EndDate>20100721</EndDate>
                    </contributionFlow>
                    <contributionFlow>
                        <Amount>8000000</Amount>
                        <StartDate>20100721</StartDate>
                        <EndDate>20100823</EndDate>
                    </contributionFlow>
                </contribution>
            </Period>
        </Payment>
    </Flows>
</member>

And I need to make a transform (or more than one, if needed) that give me this:

<XML>
<Flows>
    <Flow>
        <PaymentDate>20100621</PaymentDate>
        <StartDate>20100521</StartDate>
        <EndDate>20100621</EndDate>
        <EventType>C</EventType>
    </Flow>
    <Flow>
        <PaymentDate>20100823</PaymentDate>
        <StartDate>20100621</StartDate>
        <EndDate>20100721</EndDate>
        <EventType>A</EventType>
        <AmortizationPercent>10.0</AmortizationPercent>
    </Flow>
    <Flow>
        <PaymentDate>20100823</PaymentDate>
        <StartDate>20100721</StartDate>
        <EndDate>20100823</EndDate>
        <EventType>A</EventType>
        <AmortizationPercent>10.0</AmortizationPercent>
    </Flow>
</Flows>

It's possible?

I need to sort each <contributionFlow> (that afterwards will be renamed <Flow>) in one of two categories according to a criteria.

Not just sort, really, i need to make changes in the layout, removing a field (<Amount>) and copying another from the parent node (<Date> from <Payment>, that must call <PaymentDate> in the new).

Besides that, i need to create a <EventType> field, that need to be fill with info based on the category the <contributionFlow> fit in. But, to find out in each category the node is placed, i need to do a calculation.

I need to check and see if the field <Amount> is different than the same field from the <contributionFlow> before that (in the first, if is different from the <InicialAmount> field). If it is, the <EventType> should be populated with A, if not, with C.

More, if the <EventType> turn out to be A, there is a calculation to be made to fill the <AmortizationPercent> node.

The value in <AmortizationPercent> is given by the difference between the <Amount> value of the previous and current <contributionFlow> divided by <InicialAmount>, all that times 100.0.

I really don't even know if that is possible within a XSLT transformation, but, for now, is the only way i can make my system do such thing and this is the way that i need to be done. I just starting to learn about XSLT, so i find hard to figure out the solutions for myself.

+2  A: 

This isn't really too complicated... :)

This transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:variable name="vInitAm" select="/*/InitialAmount"/>
 <xsl:template match="node()|@*">
  <xsl:copy>
    <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="*[not(self::Flows or self::contributionFlow) and .//contributionFlow]">
   <xsl:apply-templates/>
 </xsl:template>

 <xsl:template match=
   "Period/*[not(.//contributionFlow)] | Payment/*[not(.//contributionFlow)]"/>

 <xsl:template match="Amount|InitialAmount"/>

 <xsl:template match="contributionFlow">
   <Flow>
     <PaymentDate><xsl:value-of select="../../../Date"/></PaymentDate>
     <xsl:apply-templates/>
     <xsl:variable name="vPrevAmount" select=
      "(preceding::contributionFlow[1]/Amount
      |
       $vInitAm
       )
        [last()]"/>
    <xsl:variable name="vEvType" select=
     "substring('CA', 1 + not(Amount = $vPrevAmount), 1)"/>

     <EventType><xsl:value-of select="$vEvType"/></EventType>

     <xsl:if test="$vEvType = 'A'">
       <AmortizationPercent>
         <xsl:value-of select="($vPrevAmount - Amount)*100 div $vInitAm"/>
       </AmortizationPercent>
     </xsl:if>
   </Flow>
 </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document (corrected to be well-formed):

<member>
    <InitialAmount>10000000</InitialAmount>
    <Flows>
        <Payment>
            <Date>20100621</Date>
            <Period>
                <Amount>10000000</Amount>
                <StartDate>20100521</StartDate>
                <EndDate>20100621</EndDate>
                <contribution>
                    <contributionFlow>
                        <Amount>10000000</Amount>
                        <StartDate>20100521</StartDate>
                        <EndDate>20100621</EndDate>
                    </contributionFlow>
                </contribution>
            </Period>
        </Payment>
        <Payment>
            <Date>20100823</Date>
            <Period>
                <Amount>9000000</Amount>
                <StartDate>20100621</StartDate>
                <EndDate>20100921</EndDate>
                <contribution>
                    <contributionFlow>
                        <Amount>9000000</Amount>
                        <StartDate>20100621</StartDate>
                        <EndDate>20100721</EndDate>
                    </contributionFlow>
                    <contributionFlow>
                        <Amount>8000000</Amount>
                        <StartDate>20100721</StartDate>
                        <EndDate>20100823</EndDate>
                    </contributionFlow>
                </contribution>
            </Period>
        </Payment>
    </Flows>
</member>

produces the wanted, correct result:

<Flows>
    <Flow>
        <PaymentDate>20100621</PaymentDate>
        <StartDate>20100521</StartDate>
        <EndDate>20100621</EndDate>
        <EventType>C</EventType>
    </Flow>
    <Flow>
        <PaymentDate>20100823</PaymentDate>
        <StartDate>20100621</StartDate>
        <EndDate>20100721</EndDate>
        <EventType>A</EventType>
        <AmortizationPercent>10</AmortizationPercent>
    </Flow>
    <Flow>
        <PaymentDate>20100823</PaymentDate>
        <StartDate>20100721</StartDate>
        <EndDate>20100823</EndDate>
        <EventType>A</EventType>
        <AmortizationPercent>10</AmortizationPercent>
    </Flow>
</Flows>
Dimitre Novatchev