XSLT count() is not working
I'm trying to do the count where XML/Attributes/Attribute[@Type='ComplexAttr']. If it is present then do this else do something else. However, count is always zero. Can someone tell what I'm missing. Also can someone guide me on how to improve the last part of the xslt where I'm using many xsl:if statements. Thanks in Advance.
XSLT:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="type" match="Attribute" use="Type"/>
<xsl:template match="/">
<Data Schema="XML A">
开发者_StackOverflow <xsl:apply-templates select="XML/Attributes/Attribute[generate-id() = generate-id(key('type', Type)[1])]">
<xsl:sort select="Type" order="descending"/>
</xsl:apply-templates>
<errorCodes>
<xsl:apply-templates select="XML/Attributes/Attribute" mode="errors"/>
</errorCodes>
</Data>
</xsl:template>
<xsl:template match="Attribute">
<xsl:variable name="compType">
<xsl:value-of select="count(XML/Attributes/Attribute[Type='ComplexAttr'])"/>
</xsl:variable> />
<!--<xsl:value-of select="count($compType)"/>-->
<xsl:if test="Type!='ComplexAttr'">
<Attributes type="{Type}">
<xsl:apply-templates select="key('type',Type)" mode="out"/>
<xsl:if test="Type='common'">
<Collection id="" name="test">
<ComplexAttr refId="0">
<MaskValue />
<xsl:choose>
<xsl:when test="$compType > 0">
<xsl:apply-templates select="key('type','ComplexAttr')" mode="out"/>
</xsl:when>
<xsl:otherwise>
<Attr id="" name="Color" value="000"/>
<Attr id="" name="Size" value="0010"/>
<Attr id="" name="UPC" value=""/>
<Attr id="" name="Style#" value=""/>
<Attr id="" name="Exclude" value=""/>
</xsl:otherwise>
</xsl:choose>
</ComplexAttr>
</Collection>
</xsl:if>
</Attributes>
</xsl:if>
</xsl:template>
<xsl:template match="Attribute" mode="out">
<Attr id="{id}" name="{Name}" value="{Value}"/>
</xsl:template>
<xsl:template match="Attribute[Type='ComplexAttr']" mode="out">
<Attr id="{id}" name="{Name}" value="{Value}"/>
</xsl:template>
<xsl:template match="Attribute" mode="errors">
<xsl:if test="Name['Buyer ID' or 'Coordinator ID' or 'Retail' or
'Master Pack Qty' or 'Master Pack Height' or 'Master Pack Length' or 'Master Pack Weight' or
'Master Pack Width' or 'Product Description' or 'PO Cost' or 'GTIN' or 'Vendor Model'] and Value=''">
<errorCode>"value for <xsl:value-of select="Name"/> is missing."</errorCode>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Sample XML:
<?xml version="1.0" encoding="windows-1252"?>
<XML>
<Attributes>
<Attribute>
<id>5</id>
<Name>Buyer ID</Name>
<Type>common</Type>
<Value>Lee</Value>
</Attribute>
<Attribute>
<id>331</id>
<Name>Enviornment</Name>
<Type>common</Type>
<Value>Development</Value>
</Attribute>
<Attribute>
<id>79</id>
<Name>Retail</Name>
<Type>common</Type>
<Value></Value>
</Attribute>
<Attribute>
<id>402</id>
<Name>Gender</Name>
<Type>category</Type>
<Value>Men</Value>
</Attribute>
<Attribute>
<id>1197</id>
<Name>UPC</Name>
<Type>ComplexAttr</Type>
<Value>Testing</Value>
<Path />
</Attribute>
</Attributes>
OutPut: As you can see it is not giving me the expected output. It should be Attributes/Attribute[Type='common']/Collection/ComplexAttr/ and I'm getting the following
<?xml version="1.0" encoding="utf-8"?>
<Data Schema="XML A">
<Attributes type="common">
<Attr id="5" name="Buyer ID" value="Lee" />
<Attr id="331" name="Enviornment" value="Development" />
<Attr id="79" name="Retail" value="" />
<Attr id="41" name="PlusShip" value="False" />
<Collection id="" name="test">
<ComplexAttr refId="0">
<MaskValue />
<Attr id="" name="Color" value="000" />
<Attr id="" name="Size" value="0010" />
<Attr id="" name="UPC" value="" />
<Attr id="" name="Style#" value="" />
<Attr id="" name="Exclude" value="" />
</ComplexAttr>
</Collection>
</Attributes>
<Attributes type="category">
<Attr id="402" name="Gender" value="Men" />
<Attr id="433" name="HeelHeight" value="" />
</Attributes>
<errorCodes>
<errorCode>"value for Retail is missing."</errorCode>
</errorCodes>
</Data>
<xsl:template match="Attribute"> <xsl:variable name="compType"> <xsl:value-of select="count(XML/Attributes/Attribute[Type='ComplexAttr'])"/> </xsl:variable>
The problem is here.
An Attribute
element doesn't have a child named XML
, so the text node that is child of the above variable has the value '0'.
You want:
<xsl:variable name="compType"
select="count(/XML/Attributes/Attribute[Type='ComplexAttr'])"/>
Explanation: The problem was due to using a relative XPath expression instead of an absolute one.
However, count is always zero. Can someone tell what I'm missing.
Answer #1: You're counting the number of Attribute
elements having an attribute named Type
whose value is ComplexAttr
:
<xsl:when test="count(//Attribute[@Type='ComplexAttr']) > 0">
But you should be counting the number of Attribute
elements having a child element named Type
whose value is ComplexAttr
:
<xsl:when test="count(//Attribute[Type='ComplexAttr']) > 0">
Making only this change to your XSLT causes the test to pass.
Also can someone guide me on how to improve the last part of the xslt where I'm using many xsl:if statements.
Answer #2: I would combine each of those conditions into one:
<xsl:if test="Name['Retail' or 'Environment' or
'Master Pack Qty' or 'Master Pack Height'] and Value=''">
<errorCode>"value for <xsl:value-of select="Name"/> is missing."</errorCode>
</xsl:if>
Each situation is handled identically, so there's no need to keep them separate.
This simplified stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="type" match="Attribute" use="Type"/>
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="Attribute">
<xsl:if test="Name['Buyer ID' or 'Coordinator ID' or 'Retail' or
'Master Pack Qty' or 'Master Pack Height' or 'Master Pack Length' or
'Master Pack Weight' or 'Master Pack Width' or 'Product Description' or
'PO Cost' or 'GTIN' or 'Vendor Model'] and Value=''">
<errorCode>"value for <xsl:value-of select="Name"/> is missing."</errorCode>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Produces the following output (on your input):
<errorCode>"value for Retail is missing."</errorCode>
You don't need to count: key('type','ComplexAttr')
gives you the desired Attribute
elements with Type
child equal to 'ComplexAttr'
because xsl:key
declaration.
If you want to output some default elements when there is no such Attribute
, then use:
<xsl:template match="Attribute[Type='ComplexAttr']"/>
<xsl:template match="Attribute[Type='common']">
<Attributes type="common">
<xsl:apply-templates select="key('type','common')" mode="out"/>
<Collection id="" name="test">
<ComplexAttr refId="0">
<MaskValue />
<xsl:apply-templates select="key('type','ComplexAttr')"
mode="out"/>
</ComplexAttr>
</Collection>
</Attributes>
</xsl:template>
<xsl:template match="Attribute[Type='common']
[not(key('type','ComplexAttr'))]"
priority="1">
<Attributes type="common">
<xsl:apply-templates select="key('type','common')" mode="out"/>
<Collection id="" name="test">
<ComplexAttr refId="0">
<MaskValue />
<Attr id="" name="Color" value="000"/>
<Attr id="" name="Size" value="0010"/>
<Attr id="" name="UPC" value=""/>
<Attr id="" name="Style#" value=""/>
<Attr id="" name="Exclude" value=""/>
</ComplexAttr>
</Collection>
</Attributes>
</xsl:template>
<xsl:template match="Attribute">
<Attributes type="{Type}">
<xsl:apply-templates select="key('type',Type)" mode="out"/>
</Attributes>
</xsl:template>
Note: @priority
to not rely on recovery mechanism. Just for fun, more pull style.
精彩评论