I have the following XML input and the desired output and what I am getting shown below. Idea is to set the callLegSet parameter when ever /Scripts/Script node is detected and when /Scripts/Script/Preamble is detected the callLegSet will contain the distinct set of values for the current Script element. I am not sure if this is the proper way to think about xsl an I read that a parameter can be set only once, so that may be an issue here; but if that is so, how is it that the list takes in new values ?
Can someone explain what's going on and how I may fix it.
- XSL file
<xsl:stylesheet version="1.0">
<xsl:variable name="mode" select="1" />
<xsl:key name="keyCallLeg" match="text()" use="." />
<xsl:template match="Scripts/Script">
<Script>
<xsl:apply-templates>
<xsl:with-param
name="callLegSet"
select="descendant::Command[(@command='10' or @command='11') and @mode='1']/Fields/Field[@name='type']/Value/text()
[generate-id()=generate-id(key('keyCallLeg',.)[1])]">
</xsl:with-param>
</xsl:apply-templates>
</Script>
</xsl:template>
<xsl:template match="Scripts/Script/Preamble">
<xsl:param name="callLegSet"/>
<Preamble>
<pit>
<xsl:for-each select="$callLegSet">
<xsl:variable name="currElem" select="."/>
<Field type="0" name="{$currElem}" mode="{$mode}"/>
</xsl:for-each>
</pit>
</Preamble>
</xsl:template>
<xsl:template match="Commands"></xsl:template>
<xsl:template match="Command"></xsl:template>
<xsl:template match="*|@*|text()">
<xsl:copy>
<xsl:apply-templates select="*|@*|text()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
- my Input file
<xml>
<Scripts>
<Script>
<Preamble></Preamble>
<Commands>
<Command mode="1" command="10">
<Fields>
<Field ordinal="11" name="type">
<Value>Type_A</Value>
</Field>
</Fields>
</Command>
<Command mode="1" command="11">
<Fields>
<Field ordinal="14" name="type">
<Value>Type_A</Value>
</Field>
</Fields>
</Command>
</Commands>
</Script>
<Script>
<Preamble></Preamble>
<Commands>
<Command mode="1" command="10">
<Fields>
<Field ordinal="11" name="type">
<Value>Type_A</Value>
</Field>
</Fields>
</Command>
<Command mode="1" command="11">
<Fields>
<Field ordinal="14" name="type">
<Value>Type_B</Value>
</Field>
</Fields>
</Command>
<Command mode="1" command="10">
<Fields>
<Field ordinal="11" name="type">
<Value>Type_A</Value>
</Field>
</Fields>
</Command>
<Command mode="1" command="11">
<Fields>
<Field ordinal="14" name="type">
<Value>Type_C</Value>
</Field>
</Fields>
</Command>
</Commands>
</Script>
<Script>
<Preamble></Preamble>
<Commands>
<Command mode="1" command="10">
<Fields>
<Field ordinal="11" name="type">
<Value>Type_B</Value>
</Field>
</Fields>
</Command>
<Command mode="1" command="10">
<Fields>
<Field ordinal="11" name="type">
<Value>Type_Z</Value>
</Field>
</Fields>
</Command>
</Commands>
</Script>
</Scripts>
</xml>
- Output
<xml>
<Scripts>
<Script>
<Preamble>
<pit>
<Field type="0" name="Type_A" mode="1" />
</pit>
</Preamble>
</Script>
<Script>
<Preamble>
<pit>
<Field type="0" name="Type_B" mode="1" />
<Field type="0" name="Type_C" mode="1" />
</pit>
</Preamble>
</Script>
<Script>
<Preamble>
<pit>
<Field type="0" name="Type_Z" mode="1" />
</pit>
</Preamble>
</Script>
</Scripts>
</xml>
- Desired Output
<xml>
<Scripts>
<Script>
<Preamble>
<pit>
<Field type="0" name="Type_A" mode="1" />
</pit>
</Preamble>
</Script>
<Script>
<Preamble>
<pit>
<Field type="0" name="Type_A" mode="1" />
<Field type="0" name="Type_B" mode="1" />
<Field type="0" name="Type_C" mode="1" />
</pit>
</Preamble>
</Script>
<Script>
<Preamble>
<pit>
<Field type="0" name="Type_B" mode="1" />
<Field type="0" name="Type_Z" mode="1" />
</pit>
</Preamble>
</Script>
</Scripts>
</xml>
CodePudding user response:
AFAICT, the result you want can be produced quite simply using :
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:key name="k1" match="Command" use="concat(Fields/Field/Value, '|', generate-id(..))" />
<xsl:template match="/xml">
<xml>
<Scripts>
<xsl:for-each select="Scripts/Script">
<Script>
<Preamble>
<pit>
<xsl:for-each select="Commands/Command[count(. | key('k1', concat(Fields/Field/Value, '|', generate-id(..)))[1]) = 1]">
<Field type="0" name="{Fields/Field/Value}" mode="1" />
</xsl:for-each>
</pit>
</Preamble>
</Script>
</xsl:for-each>
</Scripts>
</xml>
</xsl:template>
</xsl:stylesheet>
And, of course, even simpler in XSLT 2.0 or higher, or with a processor that supports the EXSLT set:distinct()
extension function.