Reputation: 5637
I am using XSLT 1.0 to transform a more complex xml schema into a more simplified output. I'm not focusing on accuracy of output data at this point, but primarily on the xslt processing and xpath techniques.
Looking at my source xml below, I need to visit all 'rzOutbound/body/portfolios/portfolio'
nodes. I can do that XSLT processing, and then pull the @id
attribute, <exposure>
values, etc. That is no problem.
However, I have another xml section at the bottom which I need to reference - namely,
<combinations>
So for each <portfolio>
node I visit, I need to look up the @id
attribute value inside combinations/portfolio
and verify the combination of portfolio/key1
and portfolio/key2
.
For example, if I come across this combination, I know I'm dealing with "VM" (or Variation Margin, in financial terms) :
<key1 id='DummyCounterpartyIRS'></key1>
<key2 id='MTM'></key2>
whereas in this case I'm dealing with "IM" (Initial Margin):
<portfolio id='35'>
<key1 id='DummyCounterpartyIRS'></key1>
<key2 id='InternalVaR_IRS_CCH'></key2>
</portfolio>
So do I start my template iteration at the 'rzOutbound/body/portfolios/portfolio'
node level, or do I start my iteration at the combinations/portfolio
node level ? This is where I'm struggling the most, and how to do it ?
and here is some XSLT code I'm experimenting with, where I start from the bottom of the xml source with the <combinations>
node section:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
exclude-result-prefixes="xs xd" version="1.0">
<xsl:output encoding="UTF-8" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="/*">
<collection>
<xsl:apply-templates select="combinations/portfolio"/>
</collection>
</xsl:template>
<xsl:template match="combinations/portfolio">
<-- if <key1> and <key2> @id attrib values are acceptable, then apply the
next template and select rzOutbound/body/portfolios/portfolio node
where the @id is a match -->
<xsl:apply-templates select="/razorOutbound/body/portfolios/portfolio[@id=thisID]" />
</xsl:template>
<xsl:template match="contributions/tradeContribution">
<extIA>
<Legal_ID>
<xsl:value-of select="ancestor::portfolio/@id"/>
</Legal_ID>
<Amount>
<xsl:value-of select="ancestor::portfolio/exposure"/>
</Amount>
</xsl:template>
</xsl:stylesheet>
My source xml is :
<rzOutbound>
<body>
<portfolios>
<portfolio id='39'>
<exposure>4233391.352528125</exposure>
<contributions>
<tradeContribution tradeId='CDS-RRT-002' dealId='CDS-RRT-002' desc='CRSW' contribution='2732540.4858249128'>
<hideTrade>false</hideTrade>
</tradeContribution>
<tradeContribution tradeId='CDS-RRT-001' dealId='CDS-RRT-001' desc='CRSW' contribution='1528725.384451054'>
<hideTrade>false</hideTrade>
</tradeContribution>
</contributions>
<nodeAnalysis id='ES 99.7'>
<method>EXPECTED_SHORTFALL</method>
</nodeAnalysis>
</portfolio>
<portfolio id='36'>
<exposure>1243694.4436083585</exposure>
<contributions>
<tradeContribution tradeId='IRS-RRT-001' dealId='IRS-RRT-001' desc='IRSW-FIX-FLOAT' contribution='743437.76086249948'>
<hideTrade>false</hideTrade>
</tradeContribution>
<tradeContribution tradeId='IRS-RRT-002' dealId='IRS-RRT-002' desc='IRSW-FIX-FLOAT' contribution='500256.682745859'>
<hideTrade>false</hideTrade>
</tradeContribution>
</contributions>
<nodeAnalysis id='ES 99.7'>
<method>EXPECTED_SHORTFALL</method>
</nodeAnalysis>
</portfolio>
<portfolio id='35'>
<exposure>20150788.00987801</exposure>
<contributions>
<tradeContribution tradeId='IRS-RRT-001' dealId='IRS-RRT-001' desc='IRSW-FIX-FLOAT' contribution='12045637.843246162'>
<hideTrade>false</hideTrade>
</tradeContribution>
<tradeContribution tradeId='IRS-RRT-002' dealId='IRS-RRT-002' desc='IRSW-FIX-FLOAT' contribution='8105150.1666318476'>
<hideTrade>false</hideTrade>
</tradeContribution>
</contributions>
<nodeAnalysis id='HSVaR 5D 100 ES'>
<method>INTERPOLATED_EXPECTED_SHORTFALL</method>
<percentile>100</percentile>
</nodeAnalysis>
</portfolio>
<portfolio id='38'>
<exposure>5869883.4547659159</exposure>
<contributions>
<tradeContribution tradeId='CDS-RRT-002' dealId='CDS-RRT-002' desc='CRSW' contribution='3871823.3074953556'>
<hideTrade>false</hideTrade>
</tradeContribution>
<tradeContribution tradeId='CDS-RRT-001' dealId='CDS-RRT-001' desc='CRSW' contribution='1998060.1472705603'>
<hideTrade>false</hideTrade>
</tradeContribution>
</contributions>
<nodeAnalysis id='HSVaR 5D 100 ES'>
<method>INTERPOLATED_EXPECTED_SHORTFALL</method>
<percentile>100</percentile>
</nodeAnalysis>
</portfolio>
<portfolio id='34'>
<exposure>93678157.587009192</exposure>
<contributions>
<tradeContribution tradeId='IRS-RRT-001' dealId='IRS-RRT-001' desc='IRSW-FIX-FLOAT' contribution='50713348.483467519'>
<hideTrade>false</hideTrade>
</tradeContribution>
<tradeContribution tradeId='IRS-RRT-002' dealId='IRS-RRT-002' desc='IRSW-FIX-FLOAT' contribution='42964809.103541672'>
<hideTrade>false</hideTrade>
</tradeContribution>
</contributions>
<nodeAnalysis id='MTM'>
<method>SCENARIO</method>
<exposure>true</exposure>
</nodeAnalysis>
</portfolio>
<portfolio id='37'>
<exposure>-507553339.63408583</exposure>
<contributions>
<tradeContribution tradeId='CDS-RRT-001' dealId='CDS-RRT-001' desc='CRSW' contribution='-207732702.4400686'>
<hideTrade>false</hideTrade>
</tradeContribution>
<tradeContribution tradeId='CDS-RRT-002' dealId='CDS-RRT-002' desc='CRSW' contribution='-299820637.19401723'>
<hideTrade>false</hideTrade>
</tradeContribution>
</contributions>
<nodeAnalysis id='MTM'>
<method>SCENARIO</method>
<exposure>true</exposure>
</nodeAnalysis>
</portfolio>
</portfolios>
</body>
<combinations>
<portfolio id='34'>
<key1 id='DummyCounterpartyIRS'></key1>
<key2 id='MTM'></key2>
</portfolio>
<portfolio id='35'>
<key1 id='DummyCounterpartyIRS'></key1>
<key2 id='InternalVaR_IRS_CCH'></key2>
</portfolio>
<portfolio id='38'>
<key1 id='DummyCounterpartyCDS'></key1>
<key2 id='InternalVaR_IRS_CCH'></key2>
</portfolio>
<portfolio id='39'>
<key1 id='DummyCounterpartyCDS'></key1>
<key2 id='InternalVaR_CDS_CCH'></key2>
</portfolio>
<portfolio id='36'>
<key1 id='DummyCounterpartyIRS'></key1>
<key2 id='InternalVaR_CDS_CCH'></key2>
</portfolio>
<portfolio id='37'>
<key1 id='DummyCounterpartyCDS'></key1>
<key2 id='MTM'></key2>
</portfolio>
</combinations>
</rzOutbound>
and here is a sample xml output (I'm not focusing on accuracy of output data at this point, but primarily on the xslt processing and xpath techniques.) :
<collection>
<extIA>
<AgreementID>39</AgreementID>
<Legal_ID>39</Legal_ID>
<Product/>
<Amount>4233391.352528125</Amount>
<Currency>USD</Currency>
<ValuationDate>2012-05-15</ValuationDate>
<externalSystem>IM</externalSystem>
</extIA>
<extIA>
<AgreementID>39</AgreementID>
<Legal_ID>39</Legal_ID>
<Product/>
<Amount>4233391.352528125</Amount>
<Currency>USD</Currency>
<ValuationDate>2012-05-15</ValuationDate>
</extIA>
<extIA>
<AgreementID>36</AgreementID>
<Legal_ID>36</Legal_ID>
<Product/>
<Amount>1243694.4436083585</Amount>
<Currency>USD</Currency>
<ValuationDate>2012-05-15</ValuationDate>
</extIA>
<extIA>
<AgreementID>36</AgreementID>
<Legal_ID>36</Legal_ID>
<Product/>
<Amount>1243694.4436083585</Amount>
<Currency>USD</Currency>
<ValuationDate>2012-05-15</ValuationDate>
</extIA>
<extIA>
<AgreementID>34</AgreementID>
<Legal_ID>34</Legal_ID>
<Product/>
<Amount>93678157.587009192</Amount>
<Currency>USD</Currency>
<ValuationDate>2012-05-15</ValuationDate>
</extIA>
<extIA>
<AgreementID>34</AgreementID>
<Legal_ID>34</Legal_ID>
<Product/>
<Amount>93678157.587009192</Amount>
<Currency>USD</Currency>
<ValuationDate>2012-05-15</ValuationDate>
</extIA>
<extIA>
<AgreementID>37</AgreementID>
<Legal_ID>37</Legal_ID>
<Product/>
<Amount>-507553339.63408583</Amount>
<Currency>USD</Currency>
<ValuationDate>2012-05-15</ValuationDate>
</extIA>
<extIA>
<AgreementID>37</AgreementID>
<Legal_ID>37</Legal_ID>
<Product/>
<Amount>-507553339.63408583</Amount>
<Currency>USD</Currency>
<ValuationDate>2012-05-15</ValuationDate>
</extIA>
</collection>
Upvotes: 2
Views: 107
Reputation: 117165
So do I start my template iteration at the 'rzOutbound/body/portfolios/portfolio' node level, or do I start my iteration at the combinations/portfolio node level ?
If - as it seems - both branches of the XML contain the same portfolios, then it doesn't matter which one you choose. You can always get the data from the corresponding portfolio in the other branch by using the portfolio id as the key.
For example, if I come across this combination, I know I'm dealing with "VM" (or Variation Margin, in financial terms) :
<key1 id='DummyCounterpartyIRS'></key1> <key2 id='MTM'></key2>
whereas in this case I'm dealing with "IM" (Initial Margin):
<portfolio id='35'> <key1 id='DummyCounterpartyIRS'></key1> <key2 id='InternalVaR_IRS_CCH'></key2> </portfolio>
This part is not clear. I don't see that you know any such thing from the given documents. If you want your stylesheet to "know" these things too, you must supply this information either in the stylesheet itself or by linking to an external XML document. Only then will the stylesheet be able to decide "if <key1> and <key2> @id attrib values are acceptable
".
<-- if <key1> and <key2> @id attrib values are acceptable, then apply the next template and select rzOutbound/body/portfolios/portfolio node where the @id is a match --> <xsl:apply-templates select="/razorOutbound/body/portfolios/portfolio[@id=thisID]" />
I don't think this is a good pattern to use. Either put the code to execute within the if statement or - if it's too long or needs to be reused elsewhere - call a named template. <xsl:apply-templates>
is changing the context, and you should not use it if you don't want to change the context.
if I'm in the context of
<portfolio id='39'>
for example, can you give me an example of how to reference the<key1>
@id attribute located within the<combinations>
branch where id='39'?
Sure. Here's a simple example that shows how to combine the "local" data with data looked up from the "other" branch using a key:
<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:key name="comb" match="combinations/portfolio" use="@id" />
<xsl:template match="/">
<output>
<xsl:for-each select="rzOutbound/body/portfolios/portfolio">
<portfolio id="{@id}">
<exposure><xsl:value-of select="exposure"/></exposure>
<key1><xsl:value-of select="key('comb', @id)/key1/@id"/></key1>
</portfolio>
</xsl:for-each>
</output>
</xsl:template>
</xsl:stylesheet>
When applied to your input example, the result is:
<?xml version="1.0" encoding="UTF-8"?>
<output>
<portfolio id="39">
<exposure>4233391.352528125</exposure>
<key1>DummyCounterpartyCDS</key1>
</portfolio>
<portfolio id="36">
<exposure>1243694.4436083585</exposure>
<key1>DummyCounterpartyIRS</key1>
</portfolio>
<portfolio id="35">
<exposure>20150788.00987801</exposure>
<key1>DummyCounterpartyIRS</key1>
</portfolio>
<portfolio id="38">
<exposure>5869883.4547659159</exposure>
<key1>DummyCounterpartyCDS</key1>
</portfolio>
<portfolio id="34">
<exposure>93678157.587009192</exposure>
<key1>DummyCounterpartyIRS</key1>
</portfolio>
<portfolio id="37">
<exposure>-507553339.63408583</exposure>
<key1>DummyCounterpartyCDS</key1>
</portfolio>
</output>
Upvotes: 2