I am fairly new to XML/XLST processing, and am working in an environment where I must using version 1 processing. I have an XML file that is exported from an Excel spreadsheet. The file looks like so:
<?xml version="1.0" encoding="utf-8"?>
<TmData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Version="10"
Date="2012-11-07T10:11:09.017242-05:00" Format="1" Author="System" Description="Import"
Culture="en-US">
<DocumentElement>
<Risks>
<FOLDER/>
<FOLDER1>Management</FOLDER1>
<FOLDER2>Human Resources</FOLDER2>
<RISK_x0020_FOLDER>Knowledge and People</RISK_x0020_FOLDER>
<TITLE>Insufficient investment in training</TITLE>
<CODE>code001</CODE>
<RISKCATEGORY1>Securtiy</RISKCATEGORY1>
<RISKCATEGORY2>Indirect Assertion</RISKCATEGORY2>
<RISKNUMBERICVALUE1>32.5</RISKNUMBERICVALUE1>
<RISKYESNO1>1</RISKYESNO1>
<RISKYESNO2>0</RISKYESNO2>
<_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
[Risks]</_SheetName>
<_RowNumber>6</_RowNumber>
</Risks>
<Risks>
<FOLDER/>
<FOLDER1>Management</FOLDER1>
<FOLDER2>Human Resources</FOLDER2>
<RISK_x0020_FOLDER>Knowledge and People</RISK_x0020_FOLDER>
<TITLE>Over-reliance on one or a few key employees</TITLE>
<CODE>code002</CODE>
<RISKCATEGORY3>Securtity</RISKCATEGORY3>
<RISKYESNO1>0</RISKYESNO1>
<RISKYESNO2>1</RISKYESNO2>
<WEIGHT>323.5</WEIGHT>
<_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
[Risks]</_SheetName>
<_RowNumber>7</_RowNumber>
</Risks>
<Risks>
<FOLDER/>
<FOLDER1>Management</FOLDER1>
<FOLDER2>Human Resources</FOLDER2>
<RISK_x0020_FOLDER>Knowledge and People</RISK_x0020_FOLDER>
<TITLE>Inability to recruit / retain staff</TITLE>
<CODE>code003</CODE>
<_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
[Risks]</_SheetName>
<_RowNumber>8</_RowNumber>
</Risks>
<Risks>
<FOLDER/>
<FOLDER1>Management</FOLDER1>
<FOLDER2>Human Resources</FOLDER2>
<RISK_x0020_FOLDER>Knowledge and People</RISK_x0020_FOLDER>
<TITLE>Unexpected / unbudgeted cost increases</TITLE>
<CODE>code004</CODE>
<_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
[Risks]</_SheetName>
<_RowNumber>9</_RowNumber>
</Risks>
<Risks>
<FOLDER/>
<FOLDER1>Management</FOLDER1>
<FOLDER2>Financial</FOLDER2>
<RISK_x0020_FOLDER>Financial Div</RISK_x0020_FOLDER>
<TITLE>Failure to achieve margins</TITLE>
<CODE>code005</CODE>
<RISKNUMBERICVALUE1>232.5</RISKNUMBERICVALUE1>
<RISKYESNO1>1</RISKYESNO1>
<RISKYESNO2>0</RISKYESNO2>
<_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
[Risks]</_SheetName>
<_RowNumber>12</_RowNumber>
</Risks>
<Risks>
<FOLDER/>
<FOLDER1>Management</FOLDER1>
<FOLDER2>Financial</FOLDER2>
<RISK_x0020_FOLDER>Financial Div</RISK_x0020_FOLDER>
<TITLE>Adverse impact of exchange rate fluctuations</TITLE>
<CODE>code006</CODE>
<RISKYESNO1>1</RISKYESNO1>
<_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
[Risks]</_SheetName>
<_RowNumber>13</_RowNumber>
</Risks>
<Risks>
<FOLDER>ACME Manufacturing</FOLDER>
<FOLDER1/>
<FOLDER2/>
<RISK_x0020_FOLDER>Strategic / Vision</RISK_x0020_FOLDER>
<TITLE>Strategy is not implemented</TITLE>
<CODE>code008</CODE>
<RISKNUMBERICVALUE1>0</RISKNUMBERICVALUE1>
<RISKYESNO2>0</RISKYESNO2>
<WEIGHT>10000000000.58</WEIGHT>
<_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
[Risks]</_SheetName>
<_RowNumber>16</_RowNumber>
</Risks>
<Risks>
<FOLDER>ACME Manufacturing</FOLDER>
<FOLDER1/>
<FOLDER2/>
<RISK_x0020_FOLDER>Strategic / Vision</RISK_x0020_FOLDER>
<TITLE>Failure to have and execute R&D plans</TITLE>
<CODE>code009</CODE>
<RISKYESNO1>1</RISKYESNO1>
<RISKYESNO2>0</RISKYESNO2>
<_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
[Risks]</_SheetName>
<_RowNumber>17</_RowNumber>
</Risks>
<Risks>
<FOLDER>ACME Manufacturing</FOLDER>
<FOLDER1/>
<FOLDER2/>
<RISK_x0020_FOLDER>Strategic / Vision</RISK_x0020_FOLDER>
<TITLE>Risk management practices do not exist</TITLE>
<CODE>code010</CODE>
<RISKYESNO1>1</RISKYESNO1>
<RISKYESNO2>0</RISKYESNO2>
<_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
[Risks]</_SheetName>
<_RowNumber>18</_RowNumber>
</Risks>
<Risks>
<FOLDER>ACME Manufacturing</FOLDER>
<FOLDER1>Environment</FOLDER1>
<FOLDER2/>
<RISK_x0020_FOLDER>Environment Div</RISK_x0020_FOLDER>
<TITLE>Community involvement objectives are not clearly articulated</TITLE>
<CODE>code011</CODE>
<RISKYESNO1>0</RISKYESNO1>
<RISKYESNO2>0</RISKYESNO2>
<_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
[Risks]</_SheetName>
<_RowNumber>21</_RowNumber>
</Risks>
<Risks>
<FOLDER>ACME Manufacturing</FOLDER>
<FOLDER1>Environment</FOLDER1>
<FOLDER2/>
<RISK_x0020_FOLDER>Environment Div</RISK_x0020_FOLDER>
<TITLE>Time off for community involvement is no adequately controlled</TITLE>
<CODE>code012</CODE>
<RISKYESNO1>0</RISKYESNO1>
<RISKYESNO2>0</RISKYESNO2>
<_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
[Risks]</_SheetName>
<_RowNumber>22</_RowNumber>
</Risks>
<Risks>
<FOLDER>ACME Manufacturing</FOLDER>
<FOLDER1>Market</FOLDER1>
<FOLDER2/>
<RISK_x0020_FOLDER>Market Div</RISK_x0020_FOLDER>
<TITLE>Brand / reputation damage by company environmental failure</TITLE>
<CODE>Ad.358</CODE>
<RISKYESNO1>0</RISKYESNO1>
<RISKYESNO2>1</RISKYESNO2>
<_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
[Risks]</_SheetName>
<_RowNumber>25</_RowNumber>
</Risks>
<Risks>
<FOLDER>ACME Manufacturing</FOLDER>
<FOLDER1>Market</FOLDER1>
<FOLDER2/>
<RISK_x0020_FOLDER>Market Div</RISK_x0020_FOLDER>
<TITLE>Supply of raw materials affected by environmental failure</TITLE>
<CODE>CK.324</CODE>
<RISKYESNO1>0</RISKYESNO1>
<RISKYESNO2>1</RISKYESNO2>
<_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
[Risks]</_SheetName>
<_RowNumber>26</_RowNumber>
</Risks>
<Risks>
<FOLDER>ACME Manufacturing</FOLDER>
<FOLDER1>Market</FOLDER1>
<FOLDER2/>
<RISK_x0020_FOLDER>Market Div</RISK_x0020_FOLDER>
<TITLE>Loss of business through unattractive product / service offerings</TITLE>
<CODE>AABB01</CODE>
<RISKYESNO1>0</RISKYESNO1>
<RISKYESNO2>1</RISKYESNO2>
<_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
[Risks]</_SheetName>
<_RowNumber>27</_RowNumber>
</Risks>
<Risks>
<FOLDER>ACME Manufacturing</FOLDER>
<FOLDER1>Market</FOLDER1>
<FOLDER2/>
<RISK_x0020_FOLDER>Market Div</RISK_x0020_FOLDER>
<TITLE>Natural disaster</TITLE>
<CODE>CCDD03</CODE>
<RISKYESNO1>0</RISKYESNO1>
<RISKYESNO2>1</RISKYESNO2>
<_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
[Risks]</_SheetName>
<_RowNumber>28</_RowNumber>
</Risks>
</DocumentElement>
</TmData>
I need the output to look like this:
<?xml version="1.0" encoding="utf-8"?>
<TmData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
Version="10"
Date="2012-10-31T09:35:28.9068981-04:00" Format="1" Author="System" Description="Import"
Culture="en-US"><FOLDERS>
<FOLDER>
<Title/>
<FOLDERS>
<FOLDER>
<Title>Management</Title>
<FOLDERS>
<FOLDER>
<Title>Human Resources</Title>
<FOLDERS>
<FOLDER>
<Title>Knowledge and People</Title>
<Risk>
<TITLE>Insufficient investment in training</TITLE>
<CODE>code001</CODE>
<RISKCATEGORY1>Security</RISKCATEGORY1>
<RISKCATEGORY2>Indirect Assertion</RISKCATEGORY2>
<RISKNUMBERICVALUE1>32.5</RISKNUMBERICVALUE1>
<RISKYESNO1>1</RISKYESNO1>
<RISKYESNO2>0</RISKYESNO2>
</Risk>
<Risk>
<TITLE>Over-reliance on one or a few key employees</TITLE>
<CODE>code002</CODE>
<RISKCATEGORY3>Security</RISKCATEGORY3>
<RISKYESNO1>0</RISKYESNO1>
<RISKYESNO2>1</RISKYESNO2>
</Risk>
<Risk>
<TITLE>Inability to recruit / retain staff</TITLE>
<CODE>code003</CODE>
</Risk>
<Risk>
<TITLE>
Unexpected / unbudgeted cost
increases
</TITLE>
<CODE>code004</CODE>
</Risk>
</FOLDER>
</FOLDERS>
</FOLDER>
<FOLDER>
<Title>Financial</Title>
<FOLDERS>
<FOLDER>
<Title>Financial Div</Title>
<Risk>
<TITLE>Failure to achieve margins</TITLE>
<CODE>code005</CODE>
<RISKNUMBERICVALUE1>232.5</RISKNUMBERICVALUE1>
<RISKYESNO1>1</RISKYESNO1>
<RISKYESNO2>0</RISKYESNO2>
</Risk>
<Risk>
<TITLE>
Adverse impact of exchange rate
fluctuations
</TITLE>
<CODE>code006</CODE>
<RISKYESNO1>1</RISKYESNO1>
</Risk>
</FOLDER>
</FOLDERS>
</FOLDER>
</FOLDERS>
</FOLDER>
</FOLDERS>
</FOLDER>
<FOLDER>
<Title>ACME Manufacturing</Title>
<FOLDERS>
<FOLDER>
<Title/>
<FOLDERS>
<FOLDER>
<Title/>
<FOLDERS>
<FOLDER>
<Title>Strategic / Vision</Title>
<Risk>
<TITLE>Strategy is not implemented</TITLE>
<CODE>code008</CODE>
<RISKNUMBERICVALUE1>0</RISKNUMBERICVALUE1>
<RISKYESNO2>0</RISKYESNO2>
<WEIGHT>10000000000.58</WEIGHT>
</Risk>
<Risk>
<TITLE>Failure to have and execute R&D plans</TITLE>
<CODE>code009</CODE>
<RISKYESNO1>1</RISKYESNO1>
<RISKYESNO2>0</RISKYESNO2>
</Risk>
<Risk>
<TITLE>Risk management practices do not exist</TITLE>
<CODE>code010</CODE>
<RISKYESNO1>1</RISKYESNO1>
<RISKYESNO2>0</RISKYESNO2>
</Risk>
</FOLDER>
</FOLDERS>
</FOLDER>
</FOLDERS>
</FOLDER>
<FOLDER>
<Title>Environment</Title>
<FOLDERS>
<FOLDER>
<Title/>
<FOLDERS>
<FOLDER>
<Title>Environment Div</Title>
<Risk>
<TITLE>
Community involvement objectives are not
clearly articulated
</TITLE>
<CODE>code011</CODE>
<RISKYESNO1>0</RISKYESNO1>
<RISKYESNO2>0</RISKYESNO2>
</Risk>
<Risk>
<TITLE>
Time off for community involvement is no
adequately controlled
</TITLE>
<CODE>code012</CODE>
<RISKYESNO1>0</RISKYESNO1>
<RISKYESNO2>0</RISKYESNO2>
</Risk>
</FOLDER>
</FOLDERS>
</FOLDER>
</FOLDERS>
</FOLDER>
<FOLDER>
<Title>Market</Title>
<FOLDERS>
<FOLDER>
<Title/>
<FOLDERS>
<FOLDER>
<Title>Market Div</Title>
<Risk>
<TITLE>
Brand / reputation damage by company
environmental failure
</TITLE>
<CODE>Ad.358</CODE>
<RISKYESNO1>0</RISKYESNO1>
<RISKYESNO2>1</RISKYESNO2>
</Risk>
<Risk>
<TITLE>
Supply of raw materials affected by
environmental failure
</TITLE>
<CODE>CK.324</CODE>
<RISKYESNO1>0</RISKYESNO1>
<RISKYESNO2>1</RISKYESNO2>
</Risk>
<Risk>
<TITLE>
Loss of business through unattractive
product / service offerings
</TITLE>
<CODE>AABB01</CODE>
<RISKYESNO1>0</RISKYESNO1>
<RISKYESNO2>1</RISKYESNO2>
</Risk>
<Risk>
<TITLE>Natural disaster</TITLE>
<CODE>CCDD03</CODE>
<RISKYESNO1>0</RISKYESNO1>
<RISKYESNO2>1</RISKYESNO2>
</Risk>
</FOLDER>
<FOLDER>
<Title>Sales Div</Title>
<Risk>
<TITLE>Failure to achieve sales quota</TITLE>
<CODE>S.001</CODE>
<RISKYESNO1>0</RISKYESNO1>
<RISKYESNO2>1</RISKYESNO2>
</Risk>
</FOLDER>
</FOLDERS>
</FOLDER>
</FOLDERS>
</FOLDER>
</FOLDERS>
</FOLDER>
</FOLDERS>
</TmData>
I have worked up the following XSLT file that will get me most of the way there, but I cannot figure out how to prevent the duplication of the FLODERS nodes. The XSLT looks like this:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>
<xsl:output method="xml" indent="yes"/>
<xsl:param name="rowSelector" select="local-name(//DocumentElement/*[1])"/>
<xsl:template match="/TmData">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:apply-templates select="DocumentElement"/>
</xsl:copy>
</xsl:template>
<xsl:template match="DocumentElement">
<FOLDERS>
<xsl:apply-templates mode="Elements"/>
</FOLDERS>
</xsl:template>
<xsl:template name="Risks">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="#* | node()">
<xsl:if test="not(starts-with(name(),'_'))">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:if>
</xsl:template>
<xsl:template match="RISK_x0020_FOLDER">
<FOLDER>
<Title>
<xsl:value-of select="."/>
</Title>
<xsl:call-template name="RiskTemplate">
<xsl:with-param name="RiskFolderName" select ="."/>
</xsl:call-template>
</FOLDER>
</xsl:template>
<xsl:template match="FOLDER |FOLDER1 |FOLDER2 |FOLDER3">
<xsl:param name="folderName"/>
<xsl:param name="folderValue"/>
<FOLDER>
<Title>
<xsl:value-of select="."/>
</Title>
<FOLDERS>
<xsl:choose>
<xsl:when test="starts-with(local-name(following-sibling::*[1]),'FOLDER')">
<xsl:apply-templates select="following-sibling::*[1]"/>
</xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="starts-with(local-name(following-sibling::*[1]),'RISK_x')">
<xsl:apply-templates select="following-sibling::*[1]"/>
</xsl:when>
</xsl:choose>
</FOLDERS>
</FOLDER>
</xsl:template>
<xsl:template name="RiskTemplate">
<xsl:param name="RiskFolderName"/>
<xsl:for-each select="//Risks[RISK_x0020_FOLDER=$RiskFolderName]">
<Risk>
<xsl:apply-templates select="#*"/>
<xsl:apply-templates select="TITLE"/>
<xsl:apply-templates select="CODE"/>
<xsl:apply-templates select="TYPE"/>
<xsl:apply-templates select="DESCRIPTION"/>
<xsl:apply-templates select="NOTES"/>
<xsl:apply-templates select="RISKCATEGORY1"/>
<xsl:apply-templates select="RISKCATEGORY2"/>
<xsl:apply-templates select="RISKCATEGORY3"/>
<xsl:apply-templates select="RISKCATEGORY4"/>
<xsl:apply-templates select="RISKMULTISELECTCATEGORY"/>
<xsl:apply-templates select="RISKNUMBERICVALUE1"/>
<xsl:apply-templates select="RISKYESNO1"/>
<xsl:apply-templates select="RISKYESNO2"/>
<xsl:apply-templates select="WEIGHT"/>
</Risk>
</xsl:for-each>
</xsl:template>
<xsl:template match="node()" mode="Elements">
<xsl:choose>
<xsl:when test="local-name() = $rowSelector">
<xsl:call-template name="Risks"/>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
The output I get from the transformation has the first block being correct with nesting, but I cannot figure out how to prevent the transform from looking at nodes it has already processed. There is a great deal of duplication, which is what I am trying to eliminate. I have been trying to figure this out for over a week now, and could really use some help. Thanks in advance to all the XML/XSLT gurus out there.
This template should solve your problem.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="1.0"
exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<!--
Initial template.
-->
<xsl:template match="/TmData">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:call-template name="folders">
<xsl:with-param name="depth" select="0"/>
<xsl:with-param name="risks" select="DocumentElement/Risks"/>
</xsl:call-template>
</xsl:copy>
</xsl:template>
<!--
This template is applied to <Risks/>, once the folder for the risk
has been built.
-->
<xsl:template match="Risks" mode="folder-content">
<Risk>
<xsl:copy-of select="#*|element()[not(starts-with(local-name(), '_') or contains(local-name(), 'FOLDER'))]"/>
</Risk>
</xsl:template>
<!--
Called to build out the folders at a given depth.
params:
depth: the current folder depth.
risks: the risks that are in this folder.
-->
<xsl:template name="folders">
<xsl:param name="depth"/>
<xsl:param name="risks"/>
<FOLDERS>
<xsl:call-template name="folder">
<xsl:with-param name="depth" select="$depth"/>
<xsl:with-param name="risks" select="$risks"/>
</xsl:call-template>
</FOLDERS>
</xsl:template>
<!--
Called to build a folder. This template builds the folder for the first risk
in the risks parameter. It then creates the nested folders for that risk, by
calling the folders template with the risks that are in the folder. Finally,
the template creates more folders at the same depth, by calling itself with
the risks that were not in this folder.
params:
depth: the current folder depth.
risks: the risks that are in this folder.
-->
<xsl:template name="folder">
<xsl:param name="depth"/>
<xsl:param name="risks"/>
<xsl:if test="$risks">
<xsl:variable name="element-name">
<xsl:choose>
<xsl:when test="$depth=0">FOLDER</xsl:when>
<xsl:when test="$risks[1]/*[local-name()=concat('FOLDER', $depth)]">
<xsl:value-of select="concat('FOLDER', $depth)"/>
</xsl:when>
<xsl:otherwise>RISK_x0020_FOLDER</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<!-- Build the folder for $risks[1] -->
<FOLDER>
<TITLE>
<xsl:value-of select="$risks[1]/*[local-name()=$element-name]"/>
</TITLE>
<xsl:choose>
<xsl:when test="$element-name='RISK_x0020_FOLDER'">
<xsl:apply-templates select="$risks" mode="folder-content"/>
</xsl:when>
<xsl:otherwise>
<!-- Build nested folders for all of the risks in the same folder as $risks[1]. -->
<xsl:call-template name="folders">
<xsl:with-param name="depth" select="$depth+1"/>
<xsl:with-param name="risks" select="$risks[*[local-name()=$element-name]=$risks[1]/*[local-name()=$element-name]]"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</FOLDER>
<!-- Build sibling folders for the risks that are not in the same folder as $risks[1] -->
<xsl:call-template name="folder">
<xsl:with-param name="depth" select="$depth"/>
<xsl:with-param name="risks"
select="$risks[not(*[local-name()=$element-name]=$risks[1]/*[local-name()=$element-name])]"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
For cases like this, I would avoid applying templates. It is a lot easier to create a set of the things to be processed and then use recursive call templates to do the processing.
Related
I have the following XML which contains the order details in single element.
<?xml version="1.0" encoding="UTF-8"?>
<MESSAGE xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<MESSAGE_ID>361155</MESSAGE_ID>
<NAME>Header123</NAME>
<HEADERS>
<HEADER>
<ACTION_COUNT>1</ACTION_COUNT>
<ACTION_DESC>
<DAILY_LOAD>
<LOAD_NO>1</LOAD_NO>
<CUSTOMER_NO>09656951</CUSTOMER_NO>
<REFERENCE xsi:nil="1"/>
<SERIAL>450255470000403803</SERIAL>
<ORDERS>
<ORDER>
<ITEM>5000128762885</ITEM>
<DETAILS>4582;Robert and Co;8;5526;SWD</DETAILS>
<EMP_NO>13</EMP_NO>
<USE_BY_DATE>20110611</USE_BY_DATE>
<DEPOT>5000128910035</DEPOT>
</ORDER>
<ORDER>
<ITEM>5000128853613</ITEM>
<DETAILS>5000;Anne and Co;9;2020;ATM</DETAILS>
<EMP_NO>5</EMP_NO>
<USE_BY_DATE>20110613</USE_BY_DATE>
<DEPOT>5000128910035</DEPOT>
</ORDER>
</ORDERS>
</DAILY_LOAD>
</ACTION_DESC>
</HEADER>
</HEADERS>
<LIST_ID>23689</LIST_ID>
<TRAILER>TEST_NEEDED</TRAILER>
</MESSAGE>
I need that to be transformed into the following format.
(only the DAILY_LOAD>ORDERS section should be changed as below)
.....
<ORDERS>
<ORDER>
<ITEM>5000128762885</ITEM>
<ORDER_NO>4582</ORDER_NO>
<CUSTOMER>Robert and Co</CUSTOMER>
<NO_OF_ITEMS>8</NO_OF_ITEMS>
<TOTAL>5526</TOTAL>
<LOCATION>SWD</LOCATION>
<EMP_NO>13</EMP_NO>
<USE_BY_DATE>20110611</USE_BY_DATE>
<DEPOT>5000128910035</DEPOT>
</ORDER>
<ORDER>
<ITEM>5000128853613</ITEM>
<ORDER_NO>5000</ORDER_NO>
<CUSTOMER>Anne and Co</CUSTOMER>
<NO_OF_ITEMS>9</NO_OF_ITEMS>
<TOTAL>2020</TOTAL>
<LOCATION>ATM</LOCATION>
<EMP_NO>5</EMP_NO>
<USE_BY_DATE>20110613</USE_BY_DATE>
<DEPOT>5000128910035</DEPOT>
</ORDER>
</ORDERS>
.....
The transformed XML contains no but it's divided into CUSTOMER, NO_OF_ITEMS, TOTAL and LOCATION. Any suggestion or help will be highly appreciated.
Thank you in advance.
XSLT 1.0
Using tokenizeString template as suggested in Heber.it blog. I have modified the code for producing different tag names depending on recursion level (ORDER_NO, CUSTOMER, NO_OF_ITEMS, etc).
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<!-- replaces order nodes -->
<xsl:template match="ORDER">
<ORDER>
<xsl:call-template name="tokenizeString">
<xsl:with-param name="list" select="./DETAILS"/>
<xsl:with-param name="delimiter" select="';'"/>
<xsl:with-param name="level" select="1"/>
</xsl:call-template>
</ORDER>
</xsl:template>
<!-- copy everything that doesn't match another template -->
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<!-- template to tokenize strings -->
<xsl:template name="tokenizeString">
<!--passed template parameter -->
<xsl:param name="list"/>
<xsl:param name="delimiter"/>
<xsl:param name="level"/>
<xsl:choose>
<xsl:when test="contains($list, $delimiter)">
<xsl:choose>
<xsl:when test="$level = 1">
<ITEM>
<xsl:value-of select="ITEM"/>
</ITEM>
<ORDER_NO>
<xsl:value-of select="substring-before($list,$delimiter)"/>
</ORDER_NO>
</xsl:when>
<xsl:when test="$level = 2">
<CUSTOMER>
<xsl:value-of select="substring-before($list,$delimiter)"/>
</CUSTOMER>
</xsl:when>
<xsl:when test="$level = 3">
<NO_OF_ITEMS>
<xsl:value-of select="substring-before($list,$delimiter)"/>
</NO_OF_ITEMS>
</xsl:when>
<xsl:when test="$level = 4">
<TOTAL>
<xsl:value-of select="substring-before($list,$delimiter)"/>
</TOTAL>
</xsl:when>
</xsl:choose>
<xsl:call-template name="tokenizeString">
<!-- store anything left in another variable -->
<xsl:with-param name="list" select="substring-after($list,$delimiter)"/>
<xsl:with-param name="delimiter" select="$delimiter"/>
<xsl:with-param name="level" select="$level + 1"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="$list = ''">
<xsl:text/>
</xsl:when>
<xsl:otherwise>
<LOCATION>
<xsl:value-of select="$list"/>
</LOCATION>
<EMP_NO>
<xsl:value-of select="EMP_NO"/>
</EMP_NO>
<USE_BY_DATE>
<xsl:value-of select="USE_BY_DATE"/>
</USE_BY_DATE>
<DEPOT>
<xsl:value-of select="DEPOT"/>
</DEPOT>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
XSLT 2.0
Using tokenize function you can do this:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<!-- this template replaces order nodes -->
<xsl:template match="ORDER">
<ORDER>
<xsl:variable name="fields" select="tokenize(DETAILS, ';')"/>
<ITEM>
<xsl:value-of select="ITEM"/>
</ITEM>
<ORDER_NO>
<xsl:value-of select="$fields[position()=1]"/>
</ORDER_NO>
<CUSTOMER>
<xsl:value-of select="$fields[position()=2]"/>
</CUSTOMER>
<NO_OF_ITEMS>
<xsl:value-of select="$fields[position()=3]"/>
</NO_OF_ITEMS>
<TOTAL>
<xsl:value-of select="$fields[position()=4]"/>
</TOTAL>
<LOCATION>
<xsl:value-of select="$fields[position()=5]"/>
</LOCATION>
<EMP_NO>
<xsl:value-of select="EMP_NO"/>
</EMP_NO>
<USE_BY_DATE>
<xsl:value-of select="USE_BY_DATE"/>
</USE_BY_DATE>
<DEPOT>
<xsl:value-of select="DEPOT"/>
</DEPOT>
</ORDER>
</xsl:template>
<!-- this template copies everything that doesn't match another template -->
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Actually am novice to XSLT. I have dome simple transformations using JDeveloper with for each loop while handling DB ouputs.
My current business needs an select on condition base. I have the following input xml
<?xml version = '1.0' encoding = 'UTF-8'?>
<response>
<head>
<headSeq>101</headSeq>
<date>12/03/2018</date>
</head>
<lines>
<lineItem>
<lineId>L101</lineId>
<item>Laptop</item>
<itemName>Dell</itemName>
<cId>201</cId>
</lineItem>
<lineItem>
<lineId>L102</lineId>
<item>Laptop</item>
<itemName>Dell</itemName>
<cId>202</cId>
</lineItem>
<lineItem>
<lineId>L103</lineId>
<item>Laptop</item>
<itemName>Dell</itemName>
<cId>202</cId>
</lineItem>
</lines>
<configs>
<configItem>
<configId>201</configId>
<configName>I3</configName>
</configItem>
<configItem>
<configId>202</configId>
<configName>I5</configName>
</configItem>
</configs>
</response>
Required output is
<?xml version = '1.0' encoding = 'UTF-8'?>
<ns0:lineTblRoot>
<ns0:lineTbl>
<ns0:headSeq>101</ns0:headSeq>
<ns0:lineId>L101</ns0:lineId>
<ns0:item>Laptop</ns0:item>
<ns0:itemName>Dell</ns0:itemName>
<ns0:configId>201</ns0:configId>
<ns0:configName>I3</ns0:configName>
</ns0:lineTbl>
<ns0:lineTbl>
<ns0:headSeq>101</ns0:headSeq>
<ns0:lineId>L102</ns0:lineId>
<ns0:item>Laptop</ns0:item>
<ns0:itemName>Dell</ns0:itemName>
<ns0:configId>202</ns0:configId>
<ns0:configName>I5</ns0:configName>
</ns0:lineTbl>
<ns0:lineTbl>
<ns0:headSeq>101</ns0:headSeq>
<ns0:lineId>L103</ns0:lineId>
<ns0:item>Laptop</ns0:item>
<ns0:itemName>Dell</ns0:itemName>
<ns0:configId>202</ns0:configId>
<ns0:configName>I5</ns0:configName>
</ns0:lineTbl>
</ns0:lineTblRoot>
The following XSLT doesn't yield proper result.
<xsl:template match="/">
<ns0:lineTblRoot>
<xsl:for-each select="/ns0:response/ns0:lines/ns0:lineItem">
<ns0:lineTbl>
<ns0:headSeq>
<xsl:value-of select="/ns0:response/ns0:head/ns0:headSeq"/>
</ns0:headSeq>
<ns0:lineId>
<xsl:value-of select="ns0:lineId"/>
</ns0:lineId>
<ns0:item>
<xsl:value-of select="ns0:item"/>
</ns0:item>
<ns0:itemName>
<xsl:value-of select="ns0:itemName"/>
</ns0:itemName>
<ns0:configId>
<xsl:value-of select="ns0:cId"/>
</ns0:configId>
<xsl:for-each select="/ns0:response/ns0:configs/ns0:configItem">
<xsl:choose>
<xsl:when test="/ns0:response/ns0:lines/ns0:lineItem/ns0:cId = /ns0:response/ns0:configs/ns0:configItem/ns0:configId"/>
</xsl:choose>
</xsl:for-each>
<ns0:configName>
<xsl:value-of select="/ns0:response/ns0:configs/ns0:configItem/ns0:configName"/>
</ns0:configName>
</ns0:lineTbl>
</xsl:for-each>
</ns0:lineTblRoot>
</xsl:template>
Need to select configName based on the cId in lineItem on matches with configID from configItem.
Am I miss something here? Please help.
You are matching the element with namespaces but input doesnot contains any namespaces, Use this code:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://xmlns.telenet.be/messages/GN/v001"
exclude-result-prefixes="ns0">
<xsl:template match="/">
<ns0:lineTblRoot>
<xsl:for-each select="descendant::lineItem">
<xsl:variable name="cId" select="cId"/>
<ns0:lineTbl>
<ns0:headSeq>
<xsl:value-of select="//response/head/headSeq"/>
</ns0:headSeq>
<ns0:lineId>
<xsl:value-of select="lineId"/>
</ns0:lineId>
<ns0:item>
<xsl:value-of select="item"/>
</ns0:item>
<ns0:itemName>
<xsl:value-of select="itemName"/>
</ns0:itemName>
<ns0:configId>
<xsl:value-of select="//configs/configItem/configId[. = $cId]"/>
</ns0:configId>
<ns0:configName>
<xsl:value-of select="//configs/configItem[configId = $cId]/configName"/>
</ns0:configName>
</ns0:lineTbl>
</xsl:for-each>
</ns0:lineTblRoot>
</xsl:template>
</xsl:stylesheet>
I have two xslt transformations to apply to an xml message.
<?xml version="1.0" encoding="UTF-8"?>
<ListOfBipBoxfldrlbls>
<Batch>
<ListOfFolder>
<Folder>
<FolderNum>Fldr1</FolderNum>
<BoxNumber>Box1</BoxNumber>
<BatchNumber>Batch</BatchNumber>
</Folder>
<Folder>
<FolderNum>Fldr2</FolderNum>
<BoxNumber>Box1</BoxNumber>
<BatchNumber>Batch</BatchNumber>
</Folder>
<Folder>
<FolderNum>Fldr3</FolderNum>
<BoxNumber>Box1</BoxNumber>
<BatchNumber>Batch</BatchNumber>
</Folder>
<Folder>
<FolderNum>Fldr1</FolderNum>
<BoxNumber>Box2</BoxNumber>
<BatchNumber>Batch</BatchNumber>
</Folder>
<Folder>
<FolderNum>Fldr2</FolderNum>
<BoxNumber>Box2</BoxNumber>
<BatchNumber>Batch</BatchNumber>
</Folder>
<Folder>
<FolderNum>Fldr3</FolderNum>
<BoxNumber>Box2</BoxNumber>
<BatchNumber>Batch</BatchNumber>
</Folder>
<Folder>
<FolderNum>Fldr4</FolderNum>
<BoxNumber>Box2</BoxNumber>
<BatchNumber>Batch</BatchNumber>
</Folder>
</ListOfFolder>
<ListOfBox>
<Box>
<BatchNumber>Batch</BatchNumber>
<BoxNumber>Box1</BoxNumber>
</Box>
<Box>
<BatchNumber>Batch</BatchNumber>
<BoxNumber>Box2</BoxNumber>
</Box>
</ListOfBox>
</Batch>
</ListOfBipBoxfldrlbls>
Expected Output :
Box1 Box1 Fldr1 Box1 Fldr2
Box1 Fldr3 Box2 Box2 Fldr1
Box2 Fldr2 Box2 Fldr3 Box2 Fldr4
Here is my xsl
<?xml version="1.0"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="phase-1-result">
<xsl:apply-templates select="/" mode="phase-1"/>
</xsl:variable>
<xsl:apply-templates select="$phase-1-result" mode="phase-2"/>
</xsl:template>
<xsl:template match="/" mode="phase-1">
<ListofLabels>
<xsl:for-each select="ListOfBipBoxfldrlbls/Batch/ListOfFolder/Folder">
<Label>
<FolderNum><xsl:value-of select="FolderNum"/></FolderNum>
<Box><xsl:value-of select="BoxNumber"/></Box>
<Batch><xsl:value-of select="BatchNumber"/></Batch>
</Label>
</xsl:for-each>
<xsl:for-each select="ListOfBipBoxfldrlbls/Batch/ListOfBox/Box">
<Label>
<Box><xsl:value-of select="BoxNumber"/></Box>
<Batch><xsl:value-of select="BatchNumber"/></Batch>
</Label>
</xsl:for-each>
</ListofLabels>
</xsl:template>
<xsl:template match="$phase-1-result/ListofLabels/Label" mode="phase-2">
<xsl:variable name="columns" select="3" />
<TABLE border="1">
<xsl:for-each select="$phase-1-result/ListofLabels/Label[position() mod $columns = 1]">
<TR>
<xsl:for-each select=".|following-sibling::$phase-1-result/ListofLabels/Label[position() < $columns]">
<TD>
<xsl:value-of select="." />
</TD>
</xsl:for-each>
</TR>
</xsl:for-each>
</TABLE>
</xsl:template>
</xsl:stylesheet>
I am trying to restructure the XML in the first pass and store the result in a variable "$phase-1-result" and format in the second pass using the new structure.
The problem is xmlspy is not recognizing the Variable. it is show it as undefined variable and Error: Unexpected token "$phase-1-result/ListofLabels/Label".
Can some one help me identify the Issue.
Thanks in advance.
You only need to use the variable in the initial <xsl:apply-templates select="$phase-1-result" mode="phase-2" />. After that you're "inside" the phase 1 result tree, and the match expressions and further selects don't need to use the variable, they just work within this new context:
<xsl:template match="/">
<xsl:variable name="phase-1-result">
<xsl:apply-templates select="/" mode="phase-1"/>
</xsl:variable>
<TABLE border="1">
<xsl:apply-templates mode="phase-2"
select="($phase-1-result/ListOfLabels/Label)[position() mod 3 = 1]"/>
</TABLE>
</xsl:template>
<!-- phase-1 template as before -->
<xsl:template match="Label" mode="phase-2">
<TR>
<xsl:apply-templates select=".|following-sibling::Label[position() lt 3]"
mode="columns" />
</TR>
</xsl:template>
<xsl:template match="Label" mode="columns">
<TD>
<xsl:value-of select="." />
</TD>
</xsl:template>
Here I'm doing the "select every third Label" logic at the point of applying the phase-2 template, so that template only needs to concern itself with the "me and my next two siblings" bit.
It's no different from declaring a variable containing nodes from the original input tree and then applying templates to those
<xsl:variable name="someNodes" select="/foo/bar | /foo/ping" />
<xsl:apply-templates select="$someNodes" />
<xsl:template match="bar">...</xsl:template>
The template match expressions don't care where the nodes came from, they only care what the nodes look like (is it a bar or a ping).
I want to sort the dates in xml using xslt and my date element is validated in xsd with datatype as date below is my xml and xsl
XML
<Trade xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Symbol xsi:type="TradedSymbol" Type="Swap">
<Economic xsi:type="EconomicLeg">
<Leg xsi:type="IRLegGeneratedFixed">
<Schedule xsi:type="ScheduleGeneratorFixed">
<Date>2014-06-17</Date>
</Schedule>
</Leg>
</Economic>
</Symbol>
<Symbol xsi:type="TradedSymbol" Type="Swap">
<Economic xsi:type="EconomicDetailIRLeg">
<Leg xsi:type="IRLegFloat">
<Schedule xsi:type="ScheduleGeneratorFloat">
<Date>2018-06-17</Date>
</Schedule>
</Leg>
</Economic>
</Symbol>
<Symbol xsi:type="TradedSymbol" Type="Floor">
<Economic xsi:type="EconomicDetailIRLeg">
<Leg xsi:type="IRLegFloat">
<Schedule xsi:type="ScheduleGeneratorFloat">
<Date>2000-06-17</Date>
</Schedule>
</Leg>
</Economic>
</Symbol>
</Trade>
XSD
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template name="fiExoticStructuredDeal">
<fixedIncomeExoticDeal>
<frontOfficeDealDescription>Empty decription</frontOfficeDealDescription>
<component>
<frontOfficeComponentType>
<optionDetails>
<optionStyle>European</optionStyle>
<optionDates>
<adjustedDate>
<xsl:for-each select="/Trade/Symbol/Economic/Leg/Schedule">
<xsl:sort select="concat(substring-before(Date,'-'), substring-before(substring-after(Date,'- '),'-'),substring-after(substring-after(Date,'-'),'-'))" order="ascending"/>
<xsl:choose>
<xsl:when test="position() = last()">
<xsl:value-of select="Date"/>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</adjustedDate>
</optionDates>
</optionDetails>
</frontOfficeComponentType>
</component>
</fixedIncomeExoticDeal>
</xsl:template>
</xsl:stylesheet>
I am not able sort the Date using xslt.It always gives me the last date in Schedule element.
It will be great if someone let me know if i am missing something.
Use
<xsl:sort select="Date" order="ascending"/>
I am new to XSLT and am having an issue with templates. I have an input xml file as follows:
<?xml version="1.0" encoding="UTF-8"?>
<Node>
<PHASE1_TYPE>LEFT,TOP</PHASE1_TYPE>
<PHASE1_HOL>TOK,ZUR,VIN</PHASE1_HOL>
<PHASE2_TYPE>RIGHT,BOTTOM</PHASE2_TYPE>
<PHASE2_HOL>CHF</PHASE2_HOL>
</Node>
My xslt is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:template name="tokenize">
<xsl:param name="text" select="."/>
<xsl:param name="separator" select="','"/>
<xsl:choose>
<xsl:when test="not(contains($text, $separator))">
<Holiday>
<xsl:value-of select="normalize-space($text)"/>
</Holiday>
</xsl:when>
<xsl:otherwise>
<Holiday>
<xsl:value-of select="normalize-space(
substring-before($text, $separator))"/>
</Holiday>
<xsl:call-template name="tokenize">
<xsl:with-param name="text"
select="substring-after($text, $separator)"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<Document>
<xsl:attribute name="xsi:noNamespaceSchemaLocation"
namespace="http://www.w3.org/2001/XMLSchema-instance"
>C:/usr/NONMAR~1/Output.xsd</xsl:attribute>
<xsl:for-each select="Node">
<Deal>
<DealType>
<xsl:value-of select="string(PHASE1_TYPE)"/>
</DealType>
<Holidays>
<xsl:call-template name="tokenize">
<xsl:with-param name="text" select="string(PHASE1_HOL)"/>
<xsl:with-param name="separator" select="','"/>
</xsl:call-template>
</Holidays>
</Deal>
<Deal>
<DealType>
<xsl:value-of select="string(PHASE2_TYPE)"/>
</DealType>
<Holidays>
<xsl:call-template name="tokenize">
<xsl:with-param name="text" select="string(PHASE2_HOL)"/>
<xsl:with-param name="separator" select="','"/>
</xsl:call-template>
</Holidays>
</Deal>
</xsl:for-each>
</Document>
</xsl:template>
</xsl:stylesheet>
After transformation, my output is:
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="C:/usr/NONMAR~1/Output.xsd">
<Deal>
<DealType>LEFT,TOP</DealType>
<Holidays>
<Holiday/>
</Holidays>
</Deal>
<Deal>
<DealType>RIGHT,BOTTOM</DealType>
<Holidays>
<Holiday/>
</Holidays>
</Deal>
</Document>
but the expected Output is :
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="C:/usr/NONMAR~1/Output.xsd">
<Deal>
<DealType>LEFT,TOP</DealType>
<Holidays>
<Holiday>TOK</Holiday>
<Holiday>ZUR</Holiday>
<Holiday>VIN</Holiday>
</Holidays>
</Deal>
<Deal>
<DealType>RIGHT,BOTTOM</DealType>
<Holidays>
<Holiday>CHF</Holiday>
</Holidays>
</Deal>
</Document>
I am using xslt 1.0 and do not want to use third party functions like EXSLT. Again, I am new to XSLT and do not have time right now to learn it. Would really appreciate if someone can tell me why this template is not working properly. Thanks!!
Sorry, but it's impossible to tell, from the information you provide.
On the plus side, you've taken some effort to cut your stylesheet and your sample input down in size and simplify them. That's good; I wish more new Stack Overflow users knew to do that.
On the minus side, the code you provide doesn't produce the output you show from the input you show. First of all, it's not well-formed; the end-tag for an xsl:for-each has gotten left out. And then that for-each, in the template for the document node, uses select="Node", which looks for elements named Node which are children of the document node -- but in your input, the only element child of the document node is named 'Root'. And your tokenization template wraps the individual tokens in item elements, instead of Holiday elements. When the first two slips are fixed, the stylesheet appears to produce the output you desire (modulo the Holiday/item issue):
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation=
"C:/usr/NONMAR~1/Output.xsd">
<Deal>
<DealType>LEFT,TOP</DealType>
<Holidays>
<item>TOK</item>
<item>ZUR</item>
<item>VIN</item>
</Holidays>
</Deal>
<Deal>
<DealType>RIGHT,BOTTOM</DealType>
<Holidays>
<item>CHF</item>
</Holidays>
</Deal>
</Document>