Reputation: 15
I have to change the attribute of a parent node based on a combination of parent attirbute value and and child value. My input xml is as below:
<filters>
<sheetFilter filterUsage="table" labelKey="WR" hidden="false">
<userLogin>U0002</userLogin>
<containers>
<sheetTypeRef name="WorkRequest"/>
</containers>
</sheetFilter>
<sheetFilter filterUsage="table" labelKey="AR" hidden="false">
<userLogin>U0003</userLogin>
<containers>
<sheetTypeRef name="ARRequest"/>
</containers>
</sheetFilter>
<sheetFilter filterUsage="table" labelKey="WR" hidden="false">
<userLogin>U0002</userLogin>
<containers>
<sheetTypeRef name="WorkRequest"/>
</containers>
</sheetFilter>
</filters>
In case of @labelKey
and userLogin
value combination is repeating, I have to replace the @labelKey
with a counter appeneded and the desired output should be like:
<filters>
<sheetFilter filterUsage="table" labelKey="WR1" hidden="false">
<userLogin>U0002</userLogin>
<containers>
<sheetTypeRef name="WorkRequest"/>
</containers>
</sheetFilter>
<sheetFilter filterUsage="table" labelKey="AR" hidden="false">
<userLogin>U0003</userLogin>
<containers>
<sheetTypeRef name="WorkRequest"/>
</containers>
</sheetFilter>
<sheetFilter filterUsage="table" labelKey="WR2" hidden="false">
<userLogin>U0002</userLogin>
<containers>
<sheetTypeRef name="WorkRequest"/>
</containers>
</sheetFilter>
</filters>
I have written the below xslt to apply the transformation:
<xsl:template match="*|@*">
<xsl:copy disable-output-escaping="yes">
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="sheetFilter[@labelKey='WR']">
<xsl:param name="i" select="1" />
<xsl:element name="{ local-name() }" disable-output-escaping="yes">
<xsl:for-each select="userLogin[text()='U0002']" >
<xsl:with-param name="i" select="$i +1"/>
<xsl:if test="not(../sheetFilter[@labelKey])">
<xsl:apply-templates select="../@*"/>
</xsl:if>
<xsl:attribute name="labelKey">
<xsl:value-of select="concat('WR', $i)"/>
</xsl:attribute>
</xsl:for-each>
<xsl:apply-templates select="node()"/>
</xsl:element>
</xsl:template>
But I am getting is a compiler warning below:
Compiler warnings:
Attribute 'labelKey' outside of element
And the output is not consistent, in some nodes the counter value is applied to 'labelKey' and in some nodes @lableKey itself is missing. Can anybody throw some light what went wrong in the above xslt? Also I would like to know is it possible to generalise the condition, for example match="sheetFilter[@labelKey='WR']"
is it possible to replace the WR
and U0002
with a generalised statement since I am not sure of the combination values that may repeat.
Thanks in advance. Susan
Upvotes: 0
Views: 1956
Reputation: 9627
Only for book keeping: Here a solution which keeps order and does work without for-each.
version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="kSheetFilter" match="sheetFilter " use="concat(@labelKey,'#',userLogin )" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="sheetFilter" >
<xsl:param name="pos" />
<xsl:param name="copy_cnt"/>
<xsl:copy>
<xsl:apply-templates select="@* "/>
<xsl:variable name="sheets" select="key( 'kSheetFilter',concat(@labelKey,'#',userLogin ))" />
<xsl:if test="count($sheets) > '1'">
<xsl:attribute name="labelKey" >
<xsl:value-of select="concat(@labelKey,
count(preceding-sibling::sheetFilter
[
@labelKey = current()/@labelKey and
userLogin = current()/userLogin
]) +1
)"/>
</xsl:attribute>
</xsl:if>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0
Reputation: 9627
If the original order of sheetFilter elements does not mater, you can use something based on MUENCHIAN METHOD. This will also work with xlt-1.0.
Try this:
<?xml version="1.0"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="kSheetFilter" match="sheetFilter " use="concat(@labelKey,'#',userLogin )" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="sheetFilter" >
<xsl:param name="pos" />
<xsl:param name="copy_cnt"/>
<xsl:copy>
<xsl:apply-templates select="@* "/>
<xsl:if test="$copy_cnt > '1'">
<xsl:attribute name="labelKey" >
<xsl:value-of select="concat(@labelKey, $pos)"/>
</xsl:attribute>
</xsl:if>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<xsl:copy>
<xsl:for-each
select="sheetFilter[ generate-id()=
generate-id( key( 'kSheetFilter', concat(@labelKey,'#',userLogin )
) [1])]" >
<xsl:variable name="sheets" select="key( 'kSheetFilter', concat(@labelKey,'#',userLogin ))" />
<xsl:for-each select=" $sheets" >
<xsl:apply-templates select=".">
<xsl:with-param name="pos" select="position()"/>
<xsl:with-param name ="copy_cnt" select="count($sheets)" />
</xsl:apply-templates>
</xsl:for-each>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
This will generate the following output:
<filters>
<sheetFilter filterUsage="table" labelKey="WR1" hidden="false">
<userLogin>U0002</userLogin>
<containers>
<sheetTypeRef name="WorkRequest"/>
</containers>
</sheetFilter>
<sheetFilter filterUsage="table" labelKey="WR2" hidden="false">
<userLogin>U0002</userLogin>
<containers>
<sheetTypeRef name="WorkRequest"/>
</containers>
</sheetFilter>
<sheetFilter filterUsage="table" labelKey="AR" hidden="false">
<userLogin>U0003</userLogin>
<containers>
<sheetTypeRef name="ARRequest"/>
</containers>
</sheetFilter>
</filters>
Upvotes: 0
Reputation: 3138
Your shared XSLT is not good. I have create new XSLT to get your desired output:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="filters">
<filters>
<xsl:call-template name="abc">
<xsl:with-param name="filter" select="."/>
</xsl:call-template>
</filters>
</xsl:template>
<xsl:template name="abc" match="//sheetFilter">
<xsl:param name="filter"/>
<xsl:for-each select="$filter/child::*">
<xsl:variable name="labelKey" select="@labelKey"/>
<xsl:variable name="userLogin" select="userLogin"/>
<sheetFilter filterUsage="{@filterUsage}"
labelKey="{if ( count(//sheetFilter[@labelKey = $labelKey][userLogin = $userLogin]) gt 1)
then concat(@labelKey,sum(count(preceding-sibling::sheetFilter[@labelKey=$labelKey])+1))
else @labelKey
}"
hidden="{@hidden}">
<xsl:copy-of select="child::*"/>
</sheetFilter>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
SAMPLE1 XML:
<filters>
<sheetFilter filterUsage="table" labelKey="WR" hidden="false">
<userLogin>U0002</userLogin>
<containers>
<sheetTypeRef name="WorkRequest"/>
</containers>
</sheetFilter>
<sheetFilter filterUsage="table" labelKey="AR" hidden="false">
<userLogin>U0003</userLogin>
<containers>
<sheetTypeRef name="ARRequest"/>
</containers>
</sheetFilter>
<sheetFilter filterUsage="table" labelKey="WR" hidden="false">
<userLogin>U0002</userLogin>
<containers>
<sheetTypeRef name="WorkRequest"/>
</containers>
</sheetFilter>
</filters>
OUTPUT:
<filters>
<sheetFilter filterUsage="table" labelKey="WR1" hidden="false">
<userLogin>U0002</userLogin>
<containers>
<sheetTypeRef name="WorkRequest"/>
</containers>
</sheetFilter>
<sheetFilter filterUsage="table" labelKey="AR" hidden="false">
<userLogin>U0003</userLogin>
<containers>
<sheetTypeRef name="ARRequest"/>
</containers>
</sheetFilter>
<sheetFilter filterUsage="table" labelKey="WR2" hidden="false">
<userLogin>U0002</userLogin>
<containers>
<sheetTypeRef name="WorkRequest"/>
</containers>
</sheetFilter>
</filters>
SAMPLE2 XML:
<filters>
<sheetFilter filterUsage="table" labelKey="WR" hidden="false">
<userLogin>111U0002</userLogin>
<containers>
<sheetTypeRef name="WorkRequest"/>
</containers>
</sheetFilter>
<sheetFilter filterUsage="table" labelKey="AR" hidden="false">
<userLogin>U0003</userLogin>
<containers>
<sheetTypeRef name="ARRequest"/>
</containers>
</sheetFilter>
<sheetFilter filterUsage="table" labelKey="WR" hidden="false">
<userLogin>U0002</userLogin>
<containers>
<sheetTypeRef name="WorkRequest"/>
</containers>
</sheetFilter>
</filters>
OUTPUT:
<?xml version="1.0" encoding="UTF-8"?>
<filters>
<sheetFilter filterUsage="table" labelKey="WR" hidden="false">
<userLogin>111U0002</userLogin>
<containers>
<sheetTypeRef name="WorkRequest"/>
</containers>
</sheetFilter>
<sheetFilter filterUsage="table" labelKey="AR" hidden="false">
<userLogin>U0003</userLogin>
<containers>
<sheetTypeRef name="ARRequest"/>
</containers>
</sheetFilter>
<sheetFilter filterUsage="table" labelKey="WR" hidden="false">
<userLogin>U0002</userLogin>
<containers>
<sheetTypeRef name="WorkRequest"/>
</containers>
</sheetFilter>
</filters>
SAMPLE3 XML:
<filters>
<sheetFilter filterUsage="table" labelKey="" hidden="false">
<userLogin>U0002</userLogin>
<containers>
<sheetTypeRef name="WorkRequest"/>
</containers>
</sheetFilter>
<sheetFilter filterUsage="table" labelKey="AR" hidden="false">
<userLogin>U0003</userLogin>
<containers>
<sheetTypeRef name="ARRequest"/>
</containers>
</sheetFilter>
<sheetFilter filterUsage="table" labelKey="WR" hidden="false">
<userLogin>U0002</userLogin>
<containers>
<sheetTypeRef name="WorkRequest"/>
</containers>
</sheetFilter>
</filters>
OUTPUT:
<?xml version="1.0" encoding="UTF-8"?>
<filters>
<sheetFilter filterUsage="table" labelKey="" hidden="false">
<userLogin>U0002</userLogin>
<containers>
<sheetTypeRef name="WorkRequest"/>
</containers>
</sheetFilter>
<sheetFilter filterUsage="table" labelKey="AR" hidden="false">
<userLogin>U0003</userLogin>
<containers>
<sheetTypeRef name="ARRequest"/>
</containers>
</sheetFilter>
<sheetFilter filterUsage="table" labelKey="WR" hidden="false">
<userLogin>U0002</userLogin>
<containers>
<sheetTypeRef name="WorkRequest"/>
</containers>
</sheetFilter>
</filters>
Upvotes: 0