I'm trying to stay away from a procedural approach with this solution and I'm not sure that's possible.
Here's my XML:
<countData>
<count countId="37" name="Data Response 1">
<year yearId="2013">
<month monthId="5">
<day dayId="23" countVal="6092"/>
<day dayId="24" countVal="6238"/>
<day dayId="27" countVal="6324"/>
<day dayId="28" countVal="6328"/>
<day dayId="29" countVal="3164"/>
</month>
<day dayId="23" countVal="7000"/>
<day dayId="24" countVal="7000"/>
<day dayId="27" countVal="7000"/>
<day dayId="28" countVal="7000"/>
<day dayId="29" countVal="7000"/>
</month>
</year>
</count>
<count countId="39" name="Data Response 2">
<year yearId="2013">
<month monthId="5">
<day dayId="23" countVal="675"/>
<day dayId="24" countVal="709"/>
<day dayId="27" countVal="754"/>
<day dayId="28" countVal="731"/>
<day dayId="29" countVal="377"/>
</month>
</year>
</count>
I want to apply-templates (in this example) for all count/#countIds that are 37 or 39. Here's where I am:
<xsl:template match="/">
<xsl:apply-templates mode="TimeFrame"/>
</xsl:template>
<xsl:template match="*" mode="TimeFrame">
<xsl:if test="count[#countId=37] or count[#countId=39]">
<magic>Only hitting this once for countId 37</magic>
</xsl:if>
</xsl:template>
I'm going to have quite a few of these templates with "modes" since I'm processing the same response a multitude of different ways.
Not sure how I'm missing the "range" match and only getting 1.
I'm sure it has to do with my "procedural mind". :)
Any help on this would be great!
Thanks,
Your main template, <xsl:template match="/">, runs only once - namely for the <countData> element.
Which means that you either forgot to recurse:
<xsl:template match="*" mode="TimeFrame">
<xsl:if test="count[#countId=37] or count[#countId=39]">
<magic>Only hitting this once for countId 37</magic>
</xsl:if>
<xsl:apply-templates mode="TimeFrame"/> <!-- ! -->
</xsl:template>
...or you failed to set the right context for the the main template:
<xsl:template match="/countData"><!-- ! -->
<xsl:apply-templates mode="TimeFrame"/>
</xsl:template>
<!-- or, alternatively -->
<xsl:template match="/">
<xsl:apply-templates select="countData/*" mode="TimeFrame"/>
</xsl:template>
Related
I have below mixed documents in one collection.
B3:
<creditRisk>
<characteristic>
<score>
<LID>C230</LID>
<SPID>129587</SPID>
<Sector>Finance and Insurance</Sector>
</score>
<score>
<LID>C177</LID>
<SPID>360720</SPID>
<Sector>Mining and Oil and Gas Extraction</Sector>
</score>
</characteristic>
</creditRisk>
B4:
<creditRisk>
<pit>
<score>
<LID>C230</LID>
<SPID>129587</SPID>
<LTV>1.4689503</LTV>
<LGD>0.5995806998</LGD>
<Logarithm>-0.915243031</Logarithm>
</score>
<score>
<LID>C177</LID>
<SPID>360720</SPID>
<LTV>1.524224737</LTV>
<LGD>0.8989534312</LGD>
<Logarithm>-2.292173791</Logarithm>
</score>
</pit>
</creditRisk>
At the moment to simplify the problem, I need to merge pit/score#B4 when its SPID equals to characteristic/score/SPID#B3 inside MarkLogic.
Expected Output:
<characteristic>
<score>
<default>
<LID>C230</LID>
<SPID>129587</SPID>
<LTV>1.4689503</LTV>
<LGD>0.5995806998</LGD>
<Logarithm>-0.915243031</Logarithm>
</default>
<LID>C230</LID>
<SPID>129587</SPID>
<Sector>Finance and Insurance</Sector>
</score>
<score>
<default>
<LID>C177</LID>
<SPID>360720</SPID>
<LTV>1.524224737</LTV>
<LGD>0.8989534312</LGD>
<Logarithm>-2.292173791</Logarithm>
</default>
<LID>C177</LID>
<SPID>360720</SPID>
<Sector>Mining and Oil and Gas Extraction</Sector>
</score>
</characteristic>
We are facing issue. My xsl comes out all blank results.
<xsl:template match="characteristic">
<characteristic>
<xsl:call-template name="scoreSPID">
<xsl:with-param name="characterScore" select="score"/>
</xsl:call-template>
</characteristic>
</xsl:template>
<xsl:template name="scoreSPID">
<xsl:param name="characterScore"/>
<xsl:for-each select="$characterScore">
<xsl:variable name="spid" select="SPID"/>
<score>
<xsl:for-each select="/creditRisk/pit/score[SPID eq $spid]">
<default>
<xsl:copy-of select="./node()"/>
</default>
<xsl:copy-of select="node()"/>
</xsl:for-each>
</score>
</xsl:for-each>
</xsl:template>
<xsl:template match="node()">
<xsl:apply-templates/>
</xsl:template>
How can I get the match/merge work in my xsl? Do note B3 and B4 are different dokuments in the same database.
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:cts="http://marklogic.com/cts" xmlns:fff="schema://fc.fasset/functions"
exclude-result-prefixes="#all" version="2.0">
<xsl:function name="fff:mergeModelI">
<xsl:param name="characterScore"/>
<xsl:for-each select="$characterScore">
<xsl:variable name="spid" select="SPID"/>
<xsl:variable name="query"
select="cts:path-range-query('/creditRisk/pit/score/SPID', '=', $spid)"/>
<xsl:variable name="model"
select="cts:search(fn:collection('collection-name')/creditRisk/pit/score, $query)"/>
<xsl:choose>
<xsl:when test="exists($model)">
<score>
<matched>merged</matched>
<default>
<xsl:copy-of select="$model/node()"/>
</default>
<xsl:copy-of select="node()"/>
</score>
</xsl:when>
<xsl:otherwise/>
</xsl:choose>
</xsl:for-each>
</xsl:function>
<xsl:template match="characteristic">
<characteristic>
<xsl:sequence select="fff:mergeModelI(score)"/>
</characteristic>
</xsl:template>
<xsl:template match="node()">
<xsl:apply-templates/>
</xsl:template>
</xsl:transform>
If you are looking at continuous integration, the matched/merged document should be ingested in another database with distinct collection(s).
The aforesaid and data governance/auditing necessitate the match/merge operation tracking. Here I tag <matched>merged</matched> as a recourse. The matched/merged document can be populated in another database based on the tag. You can design more comprehensive canonicalization to suit your needs.
In the predicate filter for the for-each:
<xsl:for-each select="/creditRisk/pit/score[SPID eq spid]">
you want to filter where the SPID is equal to the variable $spid. Without the $ it is looking for a sibling element spid (which doesn't exist).
It should be:
<xsl:for-each select="/creditRisk/pit/score[SPID eq $spid]">
I need to transform an fixed-length file to XML in XSLT v2.0. I saw other references but I can't apply in my XSLT. If for example, I have a text file like this:
UHL1 2016-999999 000000001 DAILY 001
ITNCC609890989099ITNCC463374755000010000.00 SANTANDER CONSUMERBOA-t-1111111111 Bank of America 2016-
ITNCC463374755017ITNCC463374755000010000.00 CONTRA SANTANDER CONSUMER 2016-
UTL110000.00 10000.00 00000010000001
The 1st line with UHL is a Header Record, the 2nd line is a Detail1 Record, 3rd line is a Detail2 Record and the last line is a Trailer Record.
I need to generate an XML file like this:
<BACSRecord>
<Header>
<Item1>UHL</Item1>
<Item2>1</Item2>
<Item3/>
<Item4>2016-</Item4>
<Item5>999999</Item5>
<Item6/>
<Item7>00</Item7>
<Item8>000000</Item8>
<Item9>1 DAILY </Item9>
<Item10>001</Item10>
<Item11/>
<Item12/>
<Item13/>
<Item14/>
</Header>
<Transaction>
<Detail1>
<Item1>ITNCC6</Item1>
<Item2>09890989</Item2>
<Item3>0</Item3>
<Item4>99</Item4>
<Item5>ITNCC4</Item5>
<Item6>63374755</Item6>
<Item7>0000</Item7>
<Item8>10000.00 </Item8>
<Item9>SANTANDER CONSUMER</Item9>
<Item10>BOA-t-1111111111 </Item10>
<Item11>Bank of America </Item11>
<Item12> 2016-</Item12>
</Detail1>
<Detail2>
<Item1>ITNCC4</Item1>
<Item2>63374755</Item2>
<Item3>0</Item3>
<Item4>17</Item4>
<Item5>ITNCC4</Item5>
<Item6>63374755</Item6>
<Item7>0000</Item7>
<Item8>10000.00 </Item8>
<Item9/>
<Item10>CONTRA</Item10>
<Item11/>
<Item12>SANTANDER CONSUMER</Item12>
<Item13> 2016-</Item13>
</Detail2>
</Transaction>
<Trailer>
<Item1>UTL</Item1>
<Item2>1</Item2>
<Item3>10000.00 </Item3>
<Item4>10000.00 </Item4>
<Item5>0000001</Item5>
<Item6>0000001</Item6>
<Item7/>
<Item8/>
</Trailer>
Is it possible to do it in XSLT?
Thank you.
Sure, something like this:
<xsl:template name="main">
<BACSRecord>
<xsl:variable name="lines" as="xs:string*" select="tokenize(unparsed-text('data.txt'), '\n')">
<Header>
<xsl:sequence select="f:header($lines[1])"/>
</Header>
<Transaction>
<xsl:for-each select="subsequence($lines, 2)">
<xsl:element name="Details{position()}">
<xsl:sequence select="f:details(.)"/>
</xsl:element>
</Transaction>
<Trailer>
<xsl:sequence select="f:trailer($lines[last()])"/>
</Header>
</xsl:template>
<xsl:function name="f:details" as="element(*)">
<xsl:param name="line" as="xs:string"/>
<xsl:sequence select="f:split(., (6,8,1,2,6,8,4,....))"/>
</xsl:function>
<xsl:function name="f:split" as="element(*)">
<xsl:param name="line" as="xs:string"/>
<xsl:param name="widths as="xs:integer*"/>
<xsl:for-each select="1 to count($widths)">
<xsl:element name="Item{.}">
<xsl:value-of select="subtring($line, sum(subsequence($widths, 1, .-1)), $widths[current()]"/>
</xsl:element>
</xsl:for-each>
</xsl:function>
I'm facing an issue in production which I'd like your help to understand what would be the best option of XSLT code change to fix it.
I have the following source structure that needs to be transformed inside my middleware:
<?xml version="1.0" encoding="UTF-8"?>
<ns0:SMRESULTS xmlns:ns0="http://www.mycompany.com/SYS/SCENARIO/VERSION">
<ns0:PREAMBLE>
<ns0:I_SITE_CODE/>
<ns0:I_DESTINATION/>
<ns0:I_FILENAME/>
<ns0:I_RECORD_TYPE/>
</ns0:PREAMBLE>
<ns0:SAMPLES>
<ns0:SAMPLE>
<ns0:S_APPROVAL_REASON/>
<ns0:D_TANK_CONFORMITY/>
<ns0:D_SAMPLE>
<ns0:D_SAMPLE_ID/>
<ns0:D_SAMPLE_VALUE/>
</ns0:D_SAMPLE>
<ns0:TESTS>
<ns0:TEST>
<ns0:T_ANALYSIS/>
<ns0:T_AUTHORISATION_COMMENT/>
<ns0:D_TEST>
<ns0:D_TEST_ID/>
<ns0:D_TEST_VALUE/>
</ns0:D_TEST>
<ns0:RESULTS>
<ns0:RESULT>
<ns0:R_VALUE/>
<ns0:D_GRDB_PROPERTY/>
<ns0:D_RESULT>
<ns0:D_RESULT_ID/>
<ns0:D_RESULT_VALUE/>
</ns0:D_RESULT>
</ns0:RESULT>
</ns0:RESULTS>
</ns0:TEST>
</ns0:TESTS>
</ns0:SAMPLE>
</ns0:SAMPLES>
</ns0:SMRESULTS>
My requirement is that whenever a "<" sign is found (characteristic D_RESULT_ID = 'Sm.Result.Min_Limit' and D_RESULT_VALUE = <![CDATA[<=600.0000]]>
the value must be transferred to 'Sm.Result.Max_Limit' characteristic and the characteristic 'Sm.Result.Min_Limit' must be blanked out.
Exemplifying: For the below source data...
<?xml version="1.0" encoding="ISO-8859-1" ?>
<SMRESULTS xmlns="http://www.mycompany.com/SYS/SCENARIO/VERSION" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<PREAMBLE>
<I_SITE_CODE>Site Code</I_SITE_CODE>
<I_DESTINATION>Destination</I_DESTINATION>
<I_FILENAME>filename.zzz</I_FILENAME>
<I_RECORD_TYPE>INSERT</I_RECORD_TYPE>
</PREAMBLE>
<SAMPLES>
<SAMPLE>
<S_APPROVAL_REASON></S_APPROVAL_REASON>
<D_TANK_CONFORMITY></D_TANK_CONFORMITY>
<D_SAMPLE>
<D_SAMPLE_ID>Sm.Sample.BatchId</D_SAMPLE_ID>
<D_SAMPLE_VALUE></D_SAMPLE_VALUE>
</D_SAMPLE>
<D_SAMPLE>
<D_SAMPLE_ID>Sm.Sample.Type</D_SAMPLE_ID>
<D_SAMPLE_VALUE></D_SAMPLE_VALUE>
</D_SAMPLE>
<D_SAMPLE>
<D_SAMPLE_ID>SM.Sample.Template_ID</D_SAMPLE_ID>
<D_SAMPLE_VALUE>SPEP-PE</D_SAMPLE_VALUE>
</D_SAMPLE>
<TESTS>
<TEST>
<T_ANALYSIS>AnalysisCode</T_ANALYSIS>
<D_TEST>
<D_TEST_ID>Sm.Test.DerivedGRDBTestMethod</D_TEST_ID>
<D_TEST_VALUE></D_TEST_VALUE>
</D_TEST>
<RESULTS>
<RESULT xsi:nil="false">
<R_VALUE>0.000</R_VALUE>
<D_GRDB_PROPERTY></D_GRDB_PROPERTY>
<D_RESULT>
<D_RESULT_ID>Sm.Result.DerivedGRDBUOM</D_RESULT_ID>
<D_RESULT_VALUE></D_RESULT_VALUE>
</D_RESULT>
<D_RESULT>
<D_RESULT_ID>Sm.Result.Min_Limit</D_RESULT_ID>
<D_RESULT_VALUE></D_RESULT_VALUE>
</D_RESULT>
<D_RESULT>
<D_RESULT_ID>Sm.Result.Max_Limit</D_RESULT_ID>
<D_RESULT_VALUE></D_RESULT_VALUE>
</D_RESULT>
<D_RESULT>
<D_RESULT_ID>Sm.Result.FailedCriticalLvl</D_RESULT_ID>
<D_RESULT_VALUE>false</D_RESULT_VALUE>
</D_RESULT>
</RESULT>
<RESULT xsi:nil="false">
<R_VALUE>0.000</R_VALUE>
<D_GRDB_PROPERTY></D_GRDB_PROPERTY>
<D_RESULT>
<D_RESULT_ID>Sm.Result.DerivedGRDBUOM</D_RESULT_ID>
<D_RESULT_VALUE></D_RESULT_VALUE>
</D_RESULT>
<D_RESULT>
<D_RESULT_ID>Sm.Result.Min_Limit</D_RESULT_ID>
<D_RESULT_VALUE></D_RESULT_VALUE>
</D_RESULT>
<D_RESULT>
<D_RESULT_ID>Sm.Result.Max_Limit</D_RESULT_ID>
<D_RESULT_VALUE></D_RESULT_VALUE>
</D_RESULT>
<D_RESULT>
<D_RESULT_ID>Sm.Result.FailedCriticalLvl</D_RESULT_ID>
<D_RESULT_VALUE>false</D_RESULT_VALUE>
</D_RESULT>
</RESULT>
<RESULT xsi:nil="false">
<R_VALUE>344.712</R_VALUE>
<D_GRDB_PROPERTY>ASH</D_GRDB_PROPERTY>
<D_RESULT>
<D_RESULT_ID>Sm.Result.DerivedGRDBUOM</D_RESULT_ID>
<D_RESULT_VALUE>59W</D_RESULT_VALUE>
</D_RESULT>
<D_RESULT>
<D_RESULT_ID>Sm.Result.Min_Limit</D_RESULT_ID>
<D_RESULT_VALUE><![CDATA[<=600.0000]]></D_RESULT_VALUE>
</D_RESULT>
<D_RESULT>
<D_RESULT_ID>Sm.Result.Max_Limit</D_RESULT_ID>
<D_RESULT_VALUE></D_RESULT_VALUE>
</D_RESULT>
<D_RESULT>
<D_RESULT_ID>Sm.Result.FailedCriticalLvl</D_RESULT_ID>
<D_RESULT_VALUE>false</D_RESULT_VALUE>
</D_RESULT>
</RESULT>
</RESULTS>
</TEST>
</TESTS>
</SAMPLE>
</SAMPLES>
</SMRESULTS>
...the desired result should be as follow:
...
<RESULT>
<R_VALUE>344.712</R_VALUE>
<D_GRDB_PROPERTY>ASH</D_GRDB_PROPERTY>
<D_RESULT>
<D_RESULT_ID>Sm.Result.DerivedGRDBUOM</D_RESULT_ID>
<D_RESULT_VALUE>59W</D_RESULT_VALUE>
</D_RESULT>
<D_RESULT>
<D_RESULT_ID>Sm.Result.Min_Limit</D_RESULT_ID>
<D_RESULT_VALUE/>
</D_RESULT>
<D_RESULT>
<D_RESULT_ID>Sm.Result.Max_Limit</D_RESULT_ID>
<D_RESULT_VALUE><![CDATA[<=600.0000]]></D_RESULT_VALUE>
</D_RESULT>
<D_RESULT>
<D_RESULT_ID>Sm.Result.FailedCriticalLvl</D_RESULT_ID>
<D_RESULT_VALUE>false</D_RESULT_VALUE>
</D_RESULT>
</RESULT>
...
I have to do this adjust in the current XSLT, which is as follow:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:a="http://www.mycompany.com/SYS/SCENARIO/VERSION" xmlns:map="java:java.util.Map" xmlns:dyn="java:com.sap.aii.mapping.api.DynamicConfiguration" xmlns:key="java:com.sap.aii.mapping.api.DynamicConfigurationKey" xmlns:javamap="java:package.xi.common.util.DateConversion">
<xsl:output method="xml" encoding="ISO-8859-1" indent="yes"/>
<xsl:param name="inputparam"/>
<xsl:param name="Region">
<xsl:text>UTC</xsl:text>
</xsl:param>
<xsl:param name="DateTimeFormat">
<xsl:text>yyyyMMdd_HHmmss</xsl:text>
</xsl:param>
<xsl:param name="DYNAMIC_CONFIG_NS_FILE">
<xsl:text>http://sap.com/xi/XI/System/File</xsl:text>
</xsl:param>
<xsl:param name="DYNAMIC_CONFIG_KEY">
<xsl:text>FileName</xsl:text>
</xsl:param>
<xsl:param name="SampleID">
<xsl:value-of select="a:SMRESULTS/a:SAMPLES/a:SAMPLE/a:S_ID_NUMERIC"/>
</xsl:param>
<!-- Call the getCurrentDateTime function from Global Services.-->
<xsl:param name="CurrentDateTime">
<xsl:if test="function-available('javamap:getCurrentDateTime')">
<xsl:value-of select="javamap:getCurrentDateTime($Region, $DateTimeFormat)"/>
</xsl:if>
</xsl:param>
<xsl:param name="DynFileName">
<xsl:value-of select="concat($SampleID,'_',$CurrentDateTime,'.xml')"/>
</xsl:param>
<!-- Set File Name in Dynamic Configuration.-->
<xsl:variable name="DynamicConf" select="map:get($inputparam, 'DynamicConfiguration')"/>
<xsl:variable name="DynamicKey" select="key:create($DYNAMIC_CONFIG_NS_FILE, $DYNAMIC_CONFIG_KEY)"/>
<xsl:variable name="FileName" select="dyn:put($DynamicConf, $DynamicKey, $DynFileName)"/>
<xsl:template match="/">
<SMRESULTS xmlns="http://www.mycompany.com/SYS/SCENARIO/VERSION">
<PREAMBLE>
<I_SITE_CODE>
<xsl:value-of select="a:SMRESULTS/a:PREAMBLE/a:I_SITE_CODE"/>
</I_SITE_CODE>
<I_DESTINATION>
<xsl:value-of select="a:SMRESULTS/a:PREAMBLE/a:I_DESTINATION"/>
</I_DESTINATION>
<I_FILENAME>
<xsl:value-of select="a:SMRESULTS/a:PREAMBLE/a:I_FILENAME"/>
</I_FILENAME>
<I_RECORD_TYPE>
<xsl:value-of select="a:SMRESULTS/a:PREAMBLE/a:I_RECORD_TYPE"/>
</I_RECORD_TYPE>
</PREAMBLE>
<SAMPLES>
<SAMPLE>
<S_APPROVAL_REASON>
<xsl:value-of select="a:SMRESULTS/a:SAMPLES/a:SAMPLE/a:S_APPROVAL_REASON"/>
</S_APPROVAL_REASON>
<D_TANK_CONFORMITY>
<xsl:value-of select="a:SMRESULTS/a:SAMPLES/a:SAMPLE/a:D_TANK_CONFORMITY"/>
</D_TANK_CONFORMITY>
<xsl:for-each select="/a:SMRESULTS/a:SAMPLES/a:SAMPLE/a:D_SAMPLE">
<D_SAMPLE>
<D_SAMPLE_ID>
<xsl:value-of select="a:D_SAMPLE_ID"/>
</D_SAMPLE_ID>
<D_SAMPLE_VALUE>
<xsl:value-of select="a:D_SAMPLE_VALUE"/>
</D_SAMPLE_VALUE>
</D_SAMPLE>
</xsl:for-each>
<TESTS>
<xsl:for-each select="a:SMRESULTS/a:SAMPLES/a:SAMPLE/a:TESTS/a:TEST">
<TEST>
<T_ANALYSIS>
<xsl:value-of select="a:T_ANALYSIS"/>
</T_ANALYSIS>
<T_AUTHORISATION_COMMENT>
<xsl:value-of select="a:T_AUTHORISATION_COMMENT"/>
</T_AUTHORISATION_COMMENT>
<xsl:for-each select="a:D_TEST">
<D_TEST>
<D_TEST_ID>
<xsl:value-of select="a:D_TEST_ID"/>
</D_TEST_ID>
<D_TEST_VALUE>
<xsl:value-of select="a:D_TEST_VALUE"/>
</D_TEST_VALUE>
</D_TEST>
</xsl:for-each>
<RESULTS>
<xsl:for-each select="a:RESULTS/a:RESULT">
<RESULT>
<R_VALUE>
<xsl:value-of select="a:R_VALUE" disable-output-escaping="yes"/>
</R_VALUE>
<D_GRDB_PROPERTY>
<xsl:value-of select="a:D_GRDB_PROPERTY" disable-output-escaping="yes"/>
</D_GRDB_PROPERTY>
<xsl:for-each select="a:D_RESULT">
<D_RESULT>
<D_RESULT_ID>
<xsl:value-of select="a:D_RESULT_ID"/>
</D_RESULT_ID>
<D_RESULT_VALUE>
<xsl:value-of select="a:D_RESULT_VALUE"/>
</D_RESULT_VALUE>
</D_RESULT>
</xsl:for-each>
</RESULT>
</xsl:for-each>
</RESULTS>
</TEST>
</xsl:for-each>
</TESTS>
</SAMPLE>
</SAMPLES>
</SMRESULTS>
</xsl:template>
</xsl:stylesheet>
I have removed some unnecessary directly-mapped fields just to make it shorter.
Any comments/suggestions will be greatly appreciated!
Thanks!
Your existing transform is horrible. You have my sympathy.
Nevertheless, you should be able to achieve the behavior you describe by modifying the template fragment for the content of <D_RESULT_VALUE> elements, along the same lines as the solution you were offered in your other question. Here's the relevant fragment of the updated stylesheet (a little wider than the actual change, so as to make the context of the XPath expressions clear; also, dedented):
<xsl:for-each select="a:D_RESULT">
<D_RESULT>
<D_RESULT_ID>
<xsl:value-of select="a:D_RESULT_ID"/>
</D_RESULT_ID>
<D_RESULT_VALUE>
<xsl:choose>
<xsl:when test="a:D_RESULT_ID='Sm.Result.Max_Limit' and ../a:D_RESULT[a:D_RESULT_ID='Sm.Result.Min_Limit'][contains(a:D_RESULT_VALUE, '<')]">
<xsl:value-of select="../a:D_RESULT[a:D_RESULT_ID='Sm.Result.Min_Limit']/a:D_RESULT_VALUE"/>
</xsl:when>
<xsl:when test="a:D_RESULT_ID='Sm.Result.Min_Limit' and contains(., '<')"/>
<xsl:otherwise>
<xsl:value-of select="a:D_RESULT_VALUE"/>
</xsl:otherwise>
</xsl:choose>
</D_RESULT_VALUE>
</D_RESULT>
</xsl:for-each>
I don't see any way to do what you want with a smaller change.
Note that this template fragment assumes that any <RESULT> element that needs to be modified contains, in addition to a <D_RESULT> with D_RESULT_ID='Sm.Result.Min_Limit', another <D_RESULT> with D_RESULT_ID='Sm.Result.Max_Limit' into which to copy the former's <D_RESULT_VALUE>. If that is not the case then the transform will simply discard the Min_Limit value.
Moreover, when a Min_Limit value is copied to a Max_Limit, any previous value of the Max_Limit is irretrievably lost (but as far as I can tell, that's what you want).
I'm trying to get a better understanding of the Muenchian grouping. I'm restricted to XSL 1.0. I was able to do groupings by attributes but I can't seem to get a grouping by element value to work.
My XML looks like this:
<?xml version="1.0"?>
<orders>
<order date="2015-01-01">
<product amount="8">Apple</product>
<product amount="1">Pear</product>
</order>
<order date="2015-01-01">
<product amount="1">Plum</product>
<product amount="5">Pear</product>
</order>
<order id="01" date="2015-01-03">
<product amount="10">Pear</product>
<product amount="4">Plum</product>
</order>
</orders>
What I'm trying to achieve is building a SVG diagram which shows how many of each fruit were ordered. So that one can easily see which is the top selling fruit per example. This would look like this (NOTE the amount-numbers are not resembling the XML above):
diagram: group by product
The code that I came up with so far is the following:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:svg="http://www.w3.org/2000/svg" >
<xsl:variable name="baseline" select="480"/>
<xsl:key name="group-by-product" match="product" use="." />
<xsl:template match="/orders">
<svg:svg >
<svg:g>
<xsl:apply-templates select="order/product[generate-id(.)=generate-id(key('group-by-product',.)[1])]" />
<!-- draw x- axis and y - axis -->
<svg:path style="stroke-width:2; stroke:black" >
<xsl:attribute name="d">
<xsl:text>M 40 100 L 40 </xsl:text>
<xsl:value-of select="480"/>
<xsl:text> L </xsl:text>
<xsl:value-of select="2* count(order) * 40 + 80" />
<xsl:text> </xsl:text>
<xsl:value-of select="$baseline"/>
<xsl:text> L 40 </xsl:text>
<xsl:value-of select="$baseline"/>
<xsl:text> Z</xsl:text>
</xsl:attribute>
</svg:path>
</svg:g>
</svg:svg>
</xsl:template>
<xsl:template match="order">
<xsl:variable name="y" select="sum(key('order-by-product',product)/#amount)"/>
<svg:rect x="{40 * position()+20}" y="{$baseline - $y}" width="30" height="{$y}" style="fill:blue"/>
<svg:text style="writing-mode:tb" x="{41 * position()+20}" y="{$baseline - $y - 10}">
<xsl:value-of select="$y" />
</svg:text>
<svg:text style="writing-mode:tb" x="{41 * position()+15}" y="{$baseline + 20}">
<xsl:value-of select="product" />
</svg:text>
</xsl:template>
</xsl:stylesheet>
I feel like I have some inconsistencies in my code and confused myself with all the different examples I already looked at..
If possible I would like to avoid "for-each" and use "apply-template" instead.
Thank you for your help!
You've got the Muenchian grouping logic right, but the template wrong - your apply-templates selects product elements:
<xsl:apply-templates select="order/product[generate-id(.)=generate-id(key('group-by-product',.)[1])]" />
but your second template matches order elements so it will never fire. You need to change it to something like
<xsl:template match="product">
<xsl:variable name="y" select="sum(key('order-by-product',.)/#amount)"/>
<svg:rect x="{40 * position()+20}" y="{$baseline - $y}" width="30" height="{$y}" style="fill:blue"/>
<svg:text style="writing-mode:tb" x="{41 * position()+20}" y="{$baseline - $y - 10}">
<xsl:value-of select="$y" />
</svg:text>
<svg:text style="writing-mode:tb" x="{41 * position()+15}" y="{$baseline + 20}">
<xsl:value-of select="." />
</svg:text>
</xsl:template>
I have a specific problem. I have to transform an XML structure to other, where the base XSD is same, different only the namespace definition. The first part is simple, because here I have to use field-mapping. The second part is the simple copy. And here is the problem. The copied "main" node contains the original xmlns attribute. I need to remove this "attribute".
The base xml:
<?xml version="1.0" encoding="UTF-8"?>
<S2SCTIcf:SCTIcfBlkCredTrf xmlns:S2SCTIcf="urn:S2SCTIcf:xsd:$SCTIcfBlkCredTrf"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:S2SCTIcf:xsd:$SCTIcfBlkCredTrf SCTIcfBlkCredTrf.xsd">
<S2SCTIcf:SndgInst>XXXXXXX0</S2SCTIcf:SndgInst>
<S2SCTIcf:RcvgInst>YYYYYYY0</S2SCTIcf:RcvgInst>
<S2SCTIcf:FileRef>2013111200800546</S2SCTIcf:FileRef>
<S2SCTIcf:SrvcId>SCT</S2SCTIcf:SrvcId>
<S2SCTIcf:TstCode>T</S2SCTIcf:TstCode>
<S2SCTIcf:FType>ICF</S2SCTIcf:FType>
<S2SCTIcf:FDtTm>2013-11-12T16:26:31</S2SCTIcf:FDtTm>
<S2SCTIcf:NumCTBlk>1</S2SCTIcf:NumCTBlk>
<S2SCTIcf:NumPCRBlk>0</S2SCTIcf:NumPCRBlk>
<S2SCTIcf:NumRFRBlk>0</S2SCTIcf:NumRFRBlk>
<S2SCTIcf:NumROIBlk>0</S2SCTIcf:NumROIBlk>
<S2SCTIcf:FIToFICstmrCdtTrf xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.02">
<GrpHdr>
<MsgId>xxddccxxaaa</MsgId>
<CreDtTm>2013-11-12T16:26:31</CreDtTm>
<NbOfTxs>1</NbOfTxs>
<TtlIntrBkSttlmAmt Ccy="EUR">469.12</TtlIntrBkSttlmAmt>
<IntrBkSttlmDt>2013-11-13</IntrBkSttlmDt>
<SttlmInf>
<SttlmMtd>CLRG</SttlmMtd>
<ClrSys>
<Prtry>ST2</Prtry>
</ClrSys>
</SttlmInf>
<InstgAgt>
<FinInstnId>
<BIC>XXXXXXX0</BIC>
</FinInstnId>
</InstgAgt>
</GrpHdr>
<CdtTrfTxInf>
<PmtId>
<EndToEndId>1114405599,1114382976</EndToEndId>
<TxId>F3232323232</TxId>
</PmtId>
<PmtTpInf>
<SvcLvl>
<Cd>SEPA</Cd>
</SvcLvl>
</PmtTpInf>
<IntrBkSttlmAmt Ccy="EUR">469.12</IntrBkSttlmAmt>
<ChrgBr>SLEV</ChrgBr>
<Dbtr>
<Nm>ddffrrddsaasas</Nm>
<PstlAdr>
<Ctry>HU</Ctry>
<AdrLine>dssdsdsdsdsdaas</AdrLine>
</PstlAdr>
</Dbtr>
<DbtrAcct>
<Id>
<IBAN>HU26XXXXXXXXXXXXXX</IBAN>
</Id>
</DbtrAcct>
<DbtrAgt>
<FinInstnId>
<BIC>CCCCHUH0</BIC>
</FinInstnId>
</DbtrAgt>
<CdtrAgt>
<FinInstnId>
<BIC>CVCVCVCVCVC</BIC>
</FinInstnId>
</CdtrAgt>
<Cdtr>
<Nm>XXXXX</Nm>
<PstlAdr>
<Ctry>DE</Ctry>
</PstlAdr>
</Cdtr>
<CdtrAcct>
<Id>
<IBAN>DE12vvvvvvvhghhg</IBAN>
</Id>
</CdtrAcct>
<RmtInf>
<Ustrd>0000000000,0000000000 </Ustrd>
</RmtInf>
</CdtTrfTxInf>
</S2SCTIcf:FIToFICstmrCdtTrf>
</S2SCTIcf:SCTIcfBlkCredTrf>
The xslt:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ns0="urn:S2SCTIcf:xsd:$SCTIcfBlkCredTrf"
xmlns:sw8="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.02"
xmlns:S2SCTScf="urn:S2SCTScf:xsd:$SCTScfBlkCredTrf" exclude-result-prefixes="xs ns0 ">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="var1_SCTIcfBlkCredTrf" select="ns0:SCTIcfBlkCredTrf"/>
<S2SCTScf:SCTScfBlkCredTrf
xsi:schemaLocation="urn:S2SCTScf:xsd:$SCTScfBlkCredTrf SCTScfBlkCredTrf.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:S2SCTScf="urn:S2SCTScf:xsd:$SCTScfBlkCredTrf">
<xsl:for-each select="$var1_SCTIcfBlkCredTrf">
<S2SCTScf:SndgInst>
<xsl:value-of select="string(ns0:RcvgInst)"/>
</S2SCTScf:SndgInst>
</xsl:for-each>
<xsl:for-each select="$var1_SCTIcfBlkCredTrf">
<S2SCTScf:RcvgInst>
<xsl:value-of select="string(ns0:SndgInst)"/>
</S2SCTScf:RcvgInst>
</xsl:for-each>
<xsl:for-each select="$var1_SCTIcfBlkCredTrf">
<S2SCTScf:SrvcId>
<xsl:value-of select="string(ns0:SrvcId)"/>
</S2SCTScf:SrvcId>
</xsl:for-each>
<xsl:for-each select="$var1_SCTIcfBlkCredTrf">
<S2SCTScf:TstCode>
<xsl:value-of select="string(ns0:TstCode)"/>
</S2SCTScf:TstCode>
</xsl:for-each>
<S2SCTScf:FType>SCF</S2SCTScf:FType>
<xsl:for-each select="$var1_SCTIcfBlkCredTrf">
<S2SCTScf:FileRef>
<xsl:value-of select="string(ns0:FileRef)"/>
</S2SCTScf:FileRef>
</xsl:for-each>
<S2SCTScf:RoutingInd>DIR</S2SCTScf:RoutingInd>
<xsl:for-each select="$var1_SCTIcfBlkCredTrf">
<S2SCTScf:FileBusDt>
<xsl:value-of select="string(ns0:FDtTm)"/>
</S2SCTScf:FileBusDt>
</xsl:for-each>
<S2SCTScf:FIToFICstmrCdtTrf xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.02">
<xsl:for-each select="$var1_SCTIcfBlkCredTrf/ns0:FIToFICstmrCdtTrf">
<GrpHdr>
<xsl:for-each select="$var1_SCTIcfBlkCredTrf/ns0:FIToFICstmrCdtTrf">
<MsgId>
<xsl:value-of select="string(sw8:GrpHdr/sw8:MsgId)"/>
</MsgId>
</xsl:for-each>
<xsl:for-each select="$var1_SCTIcfBlkCredTrf/ns0:FIToFICstmrCdtTrf">
<CreDtTm>
<xsl:value-of select="string(sw8:GrpHdr/sw8:CreDtTm)"/>
</CreDtTm>
</xsl:for-each>
<xsl:for-each select="$var1_SCTIcfBlkCredTrf/ns0:FIToFICstmrCdtTrf">
<NbOfTxs>
<xsl:value-of select="string(sw8:GrpHdr/sw8:NbOfTxs)"/>
</NbOfTxs>
</xsl:for-each>
<xsl:for-each select="$var1_SCTIcfBlkCredTrf/ns0:FIToFICstmrCdtTrf">
<xsl:variable name="var2_TtlIntrBkSttlmAmt"
select="sw8:GrpHdr/sw8:TtlIntrBkSttlmAmt"/>
<TtlIntrBkSttlmAmt>
<xsl:attribute name="Ccy" namespace="">
<xsl:value-of select="string($var2_TtlIntrBkSttlmAmt/#Ccy)"/>
</xsl:attribute>
<xsl:value-of
select="string(number(string($var2_TtlIntrBkSttlmAmt)))"/>
</TtlIntrBkSttlmAmt>
</xsl:for-each>
<xsl:for-each select="$var1_SCTIcfBlkCredTrf/ns0:FIToFICstmrCdtTrf">
<IntrBkSttlmDt>
<xsl:value-of select="string(sw8:GrpHdr/sw8:IntrBkSttlmDt)"/>
</IntrBkSttlmDt>
</xsl:for-each>
<SttlmInf>
<xsl:for-each select="$var1_SCTIcfBlkCredTrf/ns0:FIToFICstmrCdtTrf">
<SttlmMtd>
<xsl:value-of
select="string(sw8:GrpHdr/sw8:SttlmInf/sw8:SttlmMtd)"/>
</SttlmMtd>
</xsl:for-each>
<ClrSys>
<xsl:for-each select="$var1_SCTIcfBlkCredTrf/ns0:FIToFICstmrCdtTrf">
<Prtry>
<xsl:value-of
select="string(sw8:GrpHdr/sw8:SttlmInf/sw8:ClrSys/sw8:Prtry)"
/>
</Prtry>
</xsl:for-each>
</ClrSys>
</SttlmInf>
<InstdAgt>
<FinInstnId>
<xsl:for-each
select="$var1_SCTIcfBlkCredTrf/ns0:FIToFICstmrCdtTrf/sw8:GrpHdr/sw8:InstgAgt">
<BIC>
<xsl:value-of select="string(sw8:FinInstnId/sw8:BIC)"/>
</BIC>
</xsl:for-each>
</FinInstnId>
</InstdAgt>
</GrpHdr>
<xsl:copy-of select="$var1_SCTIcfBlkCredTrf/ns0:FIToFICstmrCdtTrf/sw8:CdtTrfTxInf" />
</xsl:for-each>
</S2SCTScf:FIToFICstmrCdtTrf>
</S2SCTScf:SCTScfBlkCredTrf>
</xsl:template>
</xsl:stylesheet>
The wrong part of output:
...
</InstdAgt>
</GrpHdr>
<CdtTrfTxInf xmlns:S2SCTIcf="urn:S2SCTIcf:xsd:$SCTIcfBlkCredTrf">
<PmtId>
<EndToEndId>1114405599,1114382976</EndToEndId>
<TxId>F3232323232</TxId>
...
I don't want to get the xmlns:S2SCTIcf="urn:S2SCTIcf:xsd:$SCTIcfBlkCredTrf" attribute this line.
Have someone any idea?
Thank you!
Feri
Your issue is that
<xsl:copy-of select="$var1_SCTIcfBlkCredTrf/ns0:FIToFICstmrCdtTrf/sw8:CdtTrfTxInf" />
copies the node from the original tree including its "namespace nodes", i.e. the namespace declarations that were in scope at that point in the original document. When this node is serialized any of these namespace nodes that are not already in force at this point in the output document will be declared by the serializer.
If you were able to use XSLT 2.0 then you could try setting copy-namespaces="no" on the copy-of but that isn't an option in XSLT 1.0. So instead of using copy-of you need to use templates to copy that node (and all its descendants recursively) without including the namespace nodes. The simplest way I can think of to do this is to declare two additional templates
<xsl:template match="*" mode="copy">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:apply-templates select="#*|node()" mode="copy" />
</xsl:element>
</xsl:template>
<xsl:template match="#*|text()|comment()" mode="copy">
<xsl:copy/>
</xsl:template>
and then replace that copy-of with
<xsl:apply-templates mode="copy"
select="$var1_SCTIcfBlkCredTrf/ns0:FIToFICstmrCdtTrf/sw8:CdtTrfTxInf" />
The trick here is that xsl:element is creating a new element node that happens to have the same name and namespace as the original one, rather than copying the original node, so it doesn't copy the namespace nodes.
You can use a variant of the answer here to get what you want.
Basically, you would create a template to rebuild that element without any namespaces. So you would add the following two templates to your current XSLT:
<xsl:template match="*" mode="copy-no-namespaces">
<xsl:element name="{local-name()}">
<xsl:copy-of select="#*"/>
<xsl:apply-templates select="node()" mode="copy-no-namespaces"/>
</xsl:element>
</xsl:template>
<xsl:template match="comment()| processing-instruction()" mode="copy-no-namespaces">
<xsl:copy/>
</xsl:template>
And then update your copy-of to
<xsl:apply-templates select="$var1_SCTIcfBlkCredTrf/ns0:FIToFICstmrCdtTrf/sw8:CdtTrfTxInf" mode="copy-no-namespaces"/>