Reputation: 333
I have below sample XML in which I want to check if the node exist.
Sample XML is
<document>
<item>
<ID>1000909090</ID>
<flex>
<attrGroupMany name="pageinfo">
<row>
<attr name="pagelength">10</attr>
<attr name="pagewidth">20</attr>
<attr name="pageheight">30</attr>
</row>
<row>
<attr name="pagelength">10</attr>
<attr name="pagewidth">20</attr>
</row>
</attrGroupMany>
</flex>
</item>
</document>
I am using below XSLT but is not getting converted
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="document">
<CatalogItem>
<RelationshipData>
<xsl:for-each select="item">
<Relationship>
<RelationType>PAGEDETAILSINFO</RelationType>
<RelatedItems>
<xsl:attribute name="count">
<xsl:value-of select="count(flex//attrGroupMany[@name = 'pageinfo']/row)"/>
</xsl:attribute>
<xsl:for-each select="flex//attrGroupMany[@name = 'pageinfo']/row">
<xsl:choose>
<xsl:when test="not(string-length(attr[@name = 'pageheight'] )) = 0">
<xsl:variable name="height" select="attr[@name='pageheight']"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="height" select="'0'"/>
</xsl:otherwise>
</xsl:choose>
<RelatedItem>
<xsl:attribute name="referenceKey">
<xsl:value-of select="concat('Food_And_Bev_Allergen_MVL','-',ancestor::item/ID,'-',$height)"/>
</xsl:attribute>
</RelatedItem>
</xsl:for-each>
</RelatedItems>
</Relationship>
</xsl:for-each>
</RelationshipData>
</CatalogItem>
</xsl:template>
</xsl:stylesheet>
I think the choose condition is incorrect. can you please let me know what will be the correct condition.
Upvotes: 1
Views: 11732
Reputation: 111541
You might want to adjust the default logic as Stuart suggests, but the main problem is that the height
variable scope must be corrected:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="document">
<CatalogItem>
<RelationshipData>
<xsl:for-each select="item">
<Relationship>
<RelationType>PAGEDETAILSINFO</RelationType>
<RelatedItems>
<xsl:attribute name="count">
<xsl:value-of select="count(flex//attrGroupMany[@name = 'pageinfo']/row)"/>
</xsl:attribute>
<xsl:for-each select="flex//attrGroupMany[@name = 'pageinfo']/row">
<xsl:variable name="height">
<xsl:choose>
<xsl:when test="not(attr[@name = 'pageheight'])">
<xsl:value-of select="'0'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="attr[@name='pageheight']"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<RelatedItem>
<xsl:attribute name="referenceKey">
<xsl:value-of select="concat('Food_And_Bev_Allergen_MVL','-',ancestor::item/ID,'-',$height)"/>
</xsl:attribute>
</RelatedItem>
</xsl:for-each>
</RelatedItems>
</Relationship>
</xsl:for-each>
</RelationshipData>
</CatalogItem>
</xsl:template>
</xsl:stylesheet>
After making the above changes, this input XML:
<?xml version="1.0" encoding="UTF-8"?>
<document>
<item>
<ID>1000909090</ID>
<flex>
<attrGroupMany name="pageinfo">
<row>
<attr name="pagelength">10</attr>
<attr name="pagewidth">20</attr>
<attr name="pageheight">30</attr>
</row>
<row>
<attr name="pagelength">10</attr>
<attr name="pagewidth">20</attr>
</row>
</attrGroupMany>
</flex>
</item>
</document>
Will transform to this output XML:
<?xml version="1.0" encoding="UTF-8"?>
<CatalogItem>
<RelationshipData>
<Relationship>
<RelationType>PAGEDETAILSINFO</RelationType>
<RelatedItems count="2">
<RelatedItem referenceKey="Food_And_Bev_Allergen_MVL-1000909090-30"/>
<RelatedItem referenceKey="Food_And_Bev_Allergen_MVL-1000909090-0"/>
</RelatedItems>
</Relationship>
</RelationshipData>
</CatalogItem>
Note that the following is a more natural expression of the default logic:
<xsl:variable name="height">
<xsl:choose>
<xsl:when test="attr[@name = 'pageheight']">
<xsl:value-of select="attr[@name='pageheight']"/>
</xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
</xsl:variable>
Or, if you're using XSLT 2.0, you can use the sequence idiom for default values very concisely:
<xsl:variable name="height"
select="(attr[@name='pageheight'], 0)[1]"/>
Upvotes: 3
Reputation: 107247
To determine whether the attribute is present or not, simply use not()
when the element is current.
I would reverse the logic, viz move the not present
first:
<xsl:when test="not(attr[@name='pageheight'])">
... not present, default it
Will detect if the row has no attr
elements with a @name attribute
.
Edit
You can't assign <xsl:variable>
in a branch like that - it will go out of scope within the xsl:choose
. Switch to:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="document">
<CatalogItem>
<RelationshipData>
<xsl:for-each select="item">
<Relationship>
<RelationType>PAGEDETAILSINFO</RelationType>
<RelatedItems>
<xsl:attribute name="count">
<xsl:value-of select="count(flex//attrGroupMany[@name = 'pageinfo']/row)"/>
</xsl:attribute>
<xsl:for-each select="flex//attrGroupMany[@name = 'pageinfo']/row">
<xsl:variable name="height">
<xsl:choose>
<xsl:when test="not(attr[@name = 'pageheight'])">
<xsl:text>0</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="attr[@name='pageheight']"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<RelatedItem>
<xsl:attribute name="referenceKey">
<xsl:value-of select="concat('Food_And_Bev_Allergen_MVL','-',ancestor::item/ID,'-',$height)"/>
</xsl:attribute>
</RelatedItem>
</xsl:for-each>
</RelatedItems>
</Relationship>
</xsl:for-each>
</RelationshipData>
</CatalogItem>
</xsl:template>
</xsl:stylesheet>
And the returned snippet includes:
<RelatedItems count="2">
<RelatedItem referenceKey="Food_And_Bev_Allergen_MVL-1000909090-30" />
<RelatedItem referenceKey="Food_And_Bev_Allergen_MVL-1000909090-0" />
</RelatedItems>
Upvotes: 3