Muenchian Grouping XSLT - xslt-1.0

This is my XML:
<LIGHT_DESCRIPTION_LIST>
<LIGHT_DESCRIPTION>
<LIGHT_CHARACTERISTICS>Fl</LIGHT_CHARACTERISTICS>
<LIGHT_CATEGORY>17</LIGHT_CATEGORY>
</LIGHT_DESCRIPTION>
<LIGHT_DESCRIPTION>
<LIGHT_CHARACTERISTICS>Fl</LIGHT_CHARACTERISTICS>
<LIGHT_CATEGORY>UNKNOWN</LIGHT_CATEGORY>
</LIGHT_DESCRIPTION>
<LIGHT_DESCRIPTION>
<LIGHT_CHARACTERISTICS>Fl</LIGHT_CHARACTERISTICS>
<LIGHT_CATEGORY>UNKNOWN</LIGHT_CATEGORY>
</LIGHT_DESCRIPTION>
<LIGHT_DESCRIPTION>
<LIGHT_CHARACTERISTICS>Fl</LIGHT_CHARACTERISTICS>
<LIGHT_CATEGORY>17</LIGHT_CATEGORY>
</LIGHT_DESCRIPTION>
<LIGHT_DESCRIPTION>
<LIGHT_CHARACTERISTICS>Fl</LIGHT_CHARACTERISTICS>
<LIGHT_CATEGORY>UNKNOWN</LIGHT_CATEGORY>
</LIGHT_DESCRIPTION>
<LIGHT_DESCRIPTION>
<LIGHT_CHARACTERISTICS>Fl</LIGHT_CHARACTERISTICS>
<LIGHT_CATEGORY>17</LIGHT_CATEGORY>
</LIGHT_DESCRIPTION>
<LIGHT_DESCRIPTION>
<LIGHT_CHARACTERISTICS>Fl</LIGHT_CHARACTERISTICS>
<LIGHT_CATEGORY>17</LIGHT_CATEGORY>
</LIGHT_DESCRIPTION>
</LIGHT_DESCRIPTION_LIST>
This is my XSLT:
<xsl:for-each select="LIGHT_DESCRIPTION_LIST">
<xsl:for-each select="LIGHT_DESCRIPTION">
<xsl:if test="LIGHT_CATEGORY = '17'">
<xsl:text>IRA</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
In output I had:
IRA IRA IRA IRA
I would : IRA ( if exist a light category = 17 write only one time IRA without Repetition)

Anyway, please try the code below:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="LD" match="LIGHT_DESCRIPTION" use="."/>
<xsl:variable name="Light_Desc" select="//LIGHT_DESCRIPTION"/>
<xsl:template match="LIGHT_DESCRIPTION_LIST">
<xsl:for-each select="$Light_Desc[count(. | key('LD', .)[1]) = 1]">
<xsl:if test="LIGHT_CATEGORY = '17'">
<br/>
<span style="font-family:Univers Condensed; font-size:9pt; ">
<xsl:text>IRA</xsl:text>
</span>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
You must use keys and eliminate duplicates before testing the node content.

<xsl:key name="LD" match="//LIGHT_DESCRIPTION" use="."/>
<xsl:for-each select="LIGHT_DESCRIPTION_LIST">
<xsl:for-each select="LIGHT_DESCRIPTION">
<xsl:variable name="Light_Desc" select="."/>
<xsl:for-each select="$Light_Desc[count(. | key('LD', .)[1]) = 1]">
<xsl:if test="LIGHT_CATEGORY = '17'">
<xsl:text>IRA</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
In output this give:
IRA IRA

Related

XSLT 1.0: How to determine the position of a node based on the value

thanks for taking the time!
I am trying to get the position of a node based on its value, so that I can then get corresponding entries. Please let me show you with an example, it will be easier to explain.
Here is the source XML:
<?xml version="1.0" encoding="UTF-8"?>
<sampleSourceXML>
<Table>
<Header>
<Column>Name</Column>
<Column>Surname</Column>
<Column>Title</Column>
</Header>
<Body>
<Row>
<Entry>James</Entry>
<Entry>Bond</Entry>
<Entry>Mr</Entry>
</Row>
<Row>
<Entry>Harry</Entry>
<Entry>Potter</Entry>
<Entry>Mr</Entry>
</Row>
</Body>
</Table>
</sampleSourceXML>
This is the resulting XML that I would like to achieve:
<?xml version="1.0" encoding="UTF-8"?>
<sampleResultXML>
<Person>
<FirstName>James</FirstName>
<LastName>Bond</LastName>
<Title>Mr</Title>
</Person>
<Person>
<FirstName>Harry</FirstName>
<LastName>Potter</LastName>
<Title>Mr</Title>
</Person>
</sampleResultXML>
I tried it with this XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:element name="sampleResultXML">
<xsl:for-each select="sampleSourceXML/Table/Rows/Row">
<xsl:element name="Person">
<xsl:element name="FirstName">
<xsl:value-of select="./Entry[1]/text()"></xsl:value-of>
</xsl:element>
<xsl:element name="LastName">
<xsl:value-of select="./Entry[2]/text()"></xsl:value-of>
</xsl:element>
<xsl:element name="Title">
<xsl:value-of select="./Entry[3]/text()"></xsl:value-of>
</xsl:element>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
This works.
But! The source XML can have a different order. For example the Title element can be above the Name element. So the hardcoded position in my XSLT (e.g. Entry[3]) will not work any more.
The header order and the entry order are always corresponding. So if the Column Title is in position 3, so will be the corresponding row.
So I need a way to get the position of, let's say, the Title element dynamically. So I have to go through the Column elements until I reach the one with value "Title". This position I thought I'd save in a variable (e.g. Position_Title) so that I can fill the value later like so:
<xsl:element name="Title">
<xsl:value-of select="./Entry[$Position_Title]/text()"></xsl:value-of>
</xsl:element>
However I haven't been able to find a way to do this...
Do you have any ideas how I can achieve this?
Thanks!
Nick
EDIT: Thanks to Michael for the help! Here is the final XSLT I'm using:
<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:template match="/sampleSourceXML">
<xsl:variable name="cols" select="Table/Header/Column"/>
<sampleResultXML>
<xsl:for-each select="Table/Body/Row">
<Person>
<xsl:for-each select="Entry">
<xsl:variable name="i" select="position()"/>
<xsl:variable name="elementName">
<xsl:choose>
<xsl:when test="$cols[$i]='Name'">
<xsl:value-of select="'FirstName'"/>
</xsl:when>
<xsl:when test="$cols[$i]='Surname'">
<xsl:value-of select="'LastName'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$cols[$i]"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:element name="{$elementName}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</Person>
</xsl:for-each>
</sampleResultXML>
</xsl:template>
</xsl:stylesheet>
So I need a way to get the position of, let's say, the Title element dynamically. So I have to go through the Column elements until I reach the one with value "Title". This position I thought I'd save in a variable (e.g. Position_Title) so that I can fill the value later like so:
I think it could be much simpler if you do it from the opposite direction. Try:
XSLT 1.0
<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:template match="/sampleSourceXML">
<xsl:variable name="cols" select="Table/Header/Column" />
<sampleResultXML>
<xsl:for-each select="Table/Body/Row">
<Person>
<xsl:for-each select="Entry">
<xsl:variable name="i" select="position()" />
<xsl:element name="{$cols[$i]}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</Person>
</xsl:for-each>
</sampleResultXML>
</xsl:template>
</xsl:stylesheet>

Apply templates that matchs two conditions

I need to list all the INST names but only if the "onlyTesters" node don´t exists in the "inst/idef" part of XML body above.
I know thats strange but I can´t change the XML I receive.
XML:
<river>
<station num="699">
<inst name="FLU(m)" num="1">
<idef></idef>
</inst>
<inst name="Battery(V)" num="18">
<idef>
<onlyTesters/>
</idef>
</inst>
</station>
<INST name="PLU(mm)" num="0" hasData="1" virtual="0"/>
<INST name="FLU(m)" num="1" hasData="1" virtual="0"/>
<INST name="Q(m3/s)" num="3" hasData="1" virtual="1"/>
<INST name="Battery(V)" num="18" hasData="1" virtual="0"/>
</river>
XSL:
<xsl:template match="/">
<xsl:apply-templates select="//INST[#hasData = 1 and not(//inst[#num=(current()/#num)]/idef/onlyTesters)]/#name"/>
</xsl:template>
<xsl:template match="//INST[#hasData = 1 and not(//inst[#num=(current()/#num)]/idef/onlyTesters)]/#name">
<xsl:value-of select="#name"/>,
</xsl:template>
I´m having no match.
This is the result I expect:
PLU(mm),FLU(m),Q(m3/s)
You can achieve this with only one template:
<xsl:template match="/">
<xsl:for-each select="//INST[#hasData='1' and not(#name=//inst[idef/onlyTesters]/#name)]">
<xsl:value-of select="#name"/>
<xsl:if test="position() != last()">, </xsl:if>
</xsl:for-each>
</xsl:template>
Output is:
PLU(mm), FLU(m), Q(m3/s)
Cross-references are best resolved using a key - for example:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8" />
<xsl:key name="inst" match="inst" use="#name" />
<xsl:template match="/river">
<xsl:for-each select="INST[#hasData = 1 and not(key('inst', #name)/idef/onlyTesters)]">
<xsl:value-of select="#name"/>
<xsl:if test="position() != last()">,</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Or even simpler:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8" />
<xsl:key name="exclude" match="onlyTesters" use="ancestor::inst/#name" />
<xsl:template match="/river">
<xsl:for-each select="INST[#hasData = 1 and not(key('exclude', #name))]">
<xsl:value-of select="#name"/>
<xsl:if test="position() != last()">, </xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

xslt mapping - DB collections

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>

Iterate through xml nodes within XSLT

With in an xslt 1.0. I am calling a java function getTierByBundleId which returns below xml. I want to iterate through each Tier using for each. How can i do that
<xsl:variable name="varTierList" select="testclass:getTierByBundleId($bid,$ApplicationId)"/>
Xml returned by function getTierByBundleId
<TierList>
<Tier>
<TierId>1</TierId>
<Name>test</Name>
<Type>2</Type>
<Price>10</Price>
</Tier>
<Tier>
<TierId>2</TierId>
<Name>test</Name>
<Type>3</Type>
<Price>11</Price>
</Tier>
</TierList>
Here when I am trying to do xsl:for each on the variable which has the xml I am getting compilation error. How can I access each Tier from variable $varTierList
<xsl:for-each select="$varTierList/TierList/Tier">
<TierId><xsl:for each"Tierid"/>
</xsl:for-each
Below is the xslt which is generation the above TierList xml
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:foxtelclass="test.GetOrderQuote" exclude-result-prefixes="foxtelclass" extension-element-prefixes="testclass">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:if test="count(/ROWSET/ROW) > 0">
<TierList>
<xsl:for-each select="/ROWSET/ROW">
<Tier>
<TierId><xsl:value-of select="TIER_ID" /></TierId>
<Name><xsl:value-of select="NAME" /></Name>
<Type><xsl:value-of select="TIER_TYPE" /></Type>
<Price><xsl:value-of select="PRICE" /></Price>
</Tier>
</xsl:for-each>
</TierList>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
<xsl:for-each select="$varTierList/TierList/Tier"> is throwing the error message
Here is the full xslt
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:testclass="test.GetOrderQuote"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="testclass" extension-
element-prefixes="testclass">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:param name="ApplicationId"/>
<xsl:template match="/">
<ServiceList>
<xsl:variable name="unique-list" select="//ROWSET/ROW/SERVICE_ID
[not(.=following::SERVICE_ID)]"/>
<xsl:for-each select="$unique-list">
<xsl:if test=".!=0">
<Service>
<xsl:variable name="Sid" select="."/>
<ServiceInternalId>
<xsl:value-of select="."/>
</ServiceInternalId>
<BundleList>
<xsl:variable name="unique-
bundle" select="//SERVICE_ID/../BUNDLE_ID[not(.=following::BUNDLE_ID)]"/>
<xsl:for-each
select="$unique-bundle">
<xsl:variable
name="bid" select="."/>
<xsl:if
test="count(/ROWSET/ROW/SERVICE_ID[text()=$Sid]/../BUNDLE_ID[text()=$bid])> 0">
<Bundle>
<Bundle_Id>
<xsl:value-of select="$bid"/>
</Bundle_Id>
<Type>
<xsl:value-of select="../BUNDLE_TYPE"/>
</Type>
<Name>
<xsl:value-of select="../BUNDLE_NAME"/>
</Name>
<Price>
<xsl:value-of select="../BUNDLE_PRICE"/>
</Price>
<xsl:variable name="varTierList" select="testclass:getTierByBundleId
($bid,$ApplicationId)"/>
<test>
<xsl:value-of select="$varTierList"/>
</test>
<xsl:for-each select="$varTierList/TierList/Tier"><!--line causing error-->
<TierId>
<xsl:value-of select="TierId"/>
</TierId>
</xsl:for-each>
</Bundle>
</xsl:if>
</xsl:for-each>
</BundleList>
</Service>
</xsl:if>
</xsl:for-each>
</ServiceList>
</xsl:template>
</xsl:stylesheet>
Below is the text from test node which what is xml variable varTierList contains
<test><TierList>
<Tier>
<TierId>109</TierId>
<Name>Boxes</Name>
<Type>10</Type>
<Price>10</Price>
</Tier>
</TierList>
</test>
Please find below input xml
<ROWSET>
<ROW>
<SET_ID>0</SET_ID>
<SET_DATE>2014-11-09 00:00:00.0</SET_DATE>
<BUNDLE_NAME>Test</BUNDLE_NAME>
<BUNDLE_ID>131</BUNDLE_ID>
<BUNDLE_PRICE>30</BUNDLE_PRICE>
<BUNDLE_TYPE>3</BUNDLE_TYPE>
<BUNDLECOMPONENT_LIST>101100</BUNDLECOMPONENT_LIST>
<PACKAGE>10015</PACKAGE>
<PACKAGE_TYPE>5</PACKAGE_TYPE>
<COMPONENT>101100</COMPONENT>
<PRODUCT_DESC>World Movies</PRODUCT_DESC>
<RATE_AMOUNT>10</RATE_AMOUNT>
<DISCOUNT_AMOUNT>0</DISCOUNT_AMOUNT>
<SERVICE_ID>98683812</SERVICE_ID>
<CHARGE_TYPE>RC</CHARGE_TYPE>
<GUID_TOKEN>053944D794856E3FE0540010E00D30B8</GUID_TOKEN>
<NRC_LINE_ID>0</NRC_LINE_ID>
<TIERID>11</TIERID>
</ROW>
<ROW>
<SET_ID>0</SET_ID>
<SET_DATE>2014-11-09 00:00:00.0</SET_DATE>
<BUNDLE_NAME>Optional test</BUNDLE_NAME>
<BUNDLE_ID>131</BUNDLE_ID>
<BUNDLE_PRICE>30</BUNDLE_PRICE>
<BUNDLE_TYPE>3</BUNDLE_TYPE>
<BUNDLECOMPONENT_LIST>101100</BUNDLECOMPONENT_LIST>
<PACKAGE>10015</PACKAGE>
<PACKAGE_TYPE>5</PACKAGE_TYPE>
<COMPONENT>101103</COMPONENT>
<PRODUCT_DESC>RAI International</PRODUCT_DESC>
<RATE_AMOUNT>20</RATE_AMOUNT>
<DISCOUNT_AMOUNT>0</DISCOUNT_AMOUNT>
<SERVICE_ID>98683812</SERVICE_ID>
<CHARGE_TYPE>RC</CHARGE_TYPE>
<GUID_TOKEN>053944D794856E3FE0540010E00D30B8</GUID_TOKEN>
<NRC_LINE_ID>0</NRC_LINE_ID>
<TIERID>14</TIERID>
</ROW>
</ROWSET>
Hope this helps,
this is full xslt that doesn't shows any compilation error at my end
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:testclass="test.GetOrderQuote" xmlns:ext="http://exslt.org/common" exclude-result-prefixes="testclass">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:param name="ApplicationId"/>
<xsl:template match="/">
<ServiceList>
<xsl:variable name="unique-list" select="//ROWSET/ROW/SERVICE_ID[not(.=following::SERVICE_ID)]"/>
<xsl:for-each select="$unique-list">
<xsl:if test=".!=0">
<Service>
<xsl:variable name="Sid" select="."/>
<ServiceInternalId>
<xsl:value-of select="."/>
</ServiceInternalId>
<BundleList>
<xsl:variable name="unique-bundle" select="//SERVICE_ID/../BUNDLE_ID[not(.=following::BUNDLE_ID)]"/>
<xsl:for-each select="$unique-bundle">
<xsl:variable name="bid" select="."/>
<xsl:if test="count(/ROWSET/ROW/SERVICE_ID[text()=$Sid]/../BUNDLE_ID[text()=$bid])> 0">
<Bundle>
<Bundle_Id>
<xsl:value-of select="$bid"/>
</Bundle_Id>
<Type>
<xsl:value-of select="../BUNDLE_TYPE"/>
</Type>
<Name>
<xsl:value-of select="../BUNDLE_NAME"/>
</Name>
<Price>
<xsl:value-of select="../BUNDLE_PRICE"/>
</Price>
<xsl:variable name="varTierList" select="testclass:getTierByBundleId($bid,$ApplicationId)"/>
<test>
<xsl:value-of select="$varTierList"/>
</test>
<xsl:for-each select="$varTierList/TierList/Tier">
<TierId>
<xsl:value-of select="TierId"/>
</TierId>
</xsl:for-each>
</Bundle>
</xsl:if>
</xsl:for-each>
</BundleList>
</Service>
</xsl:if>
</xsl:for-each>
</ServiceList>
</xsl:template>
</xsl:stylesheet>

XSL match multiple variables with XML

I'm trying to match xsl variables i.e. key1, key2 with xml node strings.
Problem: the xsl variables can vary like key1, key2, key3, key4, until key.length...
Question: How can I modify my xsl so when the key[i] is used, then ti will display all the xml node matches.
Here's my XML:
<?xml version="1.0" encoding="UTF-8"?>
<document>
<metadata>
<field>marketing business</field>
<field>PageTitle1 One</field>
<field>marketing business link</field>
<field>planning development</field>
<field>PageTitle2 Two</field>
<field>planning development link</field>
<field>learning development</field>
<field>PageTitle3 Threee</field>
<field>learning development link</field>
</metadata>
</document>
Here's my XSL:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:variable name="key1">marketing</xsl:variable>
<xsl:variable name="key2">business</xsl:variable>
<xsl:for-each select="document/metadata/field">
<xsl:choose>
<xsl:when test="contains(.,$key1) and contains(.,$key2)">
match <xsl:value-of select="." /><br/>
</xsl:when>
<xsl:when test="contains(.,$key2)">
match <xsl:value-of select="." /><br/>
</xsl:when>
<!--... add other options here-->
<xsl:otherwise></xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
Result:
match marketing business
match marketing business link
Any help? or is there a way to put this in an array-like variable or any different approach?...
Consider putting your "keys" in a separate XML document, call it "keys.xml"
<keys>
<key>marketing</key>
<key>business</key>
</keys>
Then, you can create a single variable in your XSLT to reference this document
<xsl:variable name="keys" select="document('keys.xml')/keys" />
With this variable you can then, for example, check if your field element matches all the keys like so:
<xsl:variable name="matches" select="count($keys/key[contains(current(), .)])" />
<xsl:choose>
<xsl:when test="$matches = count($keys/key)">
Try this XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:variable name="keys" select="document('keys.xml')/keys" />
<xsl:variable name="totalkeys" select="count($keys/key)" />
<xsl:template match="/">
<xsl:for-each select="document/metadata/field">
<xsl:variable name="matches" select="count($keys/key[contains(current(), .)])" />
<xsl:choose>
<xsl:when test="$matches = $totalkeys">
matches all <xsl:value-of select="." /><br/>
</xsl:when>
<xsl:when test="$matches = 1">
matches one <xsl:value-of select="." /><br/>
</xsl:when>
<xsl:when test="$matches > 0">
matches some <xsl:value-of select="." /><br/>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>