Reputation: 582
I have a xml like this,
<categories>
<data>
<category_id>216</category_id>
<children_sort_order>217</children_sort_order>
<children_sort_order>324</children_sort_order>
<children_sort_order>395</children_sort_order>
<children_sort_order>580</children_sort_order>
<children_sort_order>506</children_sort_order>
<children_sort_order>466</children_sort_order>
<children_sort_order>626</children_sort_order>
<children_sort_order>532</children_sort_order>
<depth>0</depth>
<description/>
<name>Products</name>
<path>products</path>
<slug>products</slug>
<state>live</state>
<status>
<state>live</state>
</status>
<updated_at>2016-06-09T05:13:08Z</updated_at>
<westfield_locale>en_AU</westfield_locale>
<sort_order>0</sort_order>
</data>
<data>
<category_id>217</category_id>
<children_sort_order>218</children_sort_order>
<children_sort_order>319</children_sort_order>
<children_sort_order>232</children_sort_order>
<children_sort_order>237</children_sort_order>
<children_sort_order>244</children_sort_order>
<children_sort_order>255</children_sort_order>
<children_sort_order>225</children_sort_order>
<children_sort_order>307</children_sort_order>
<children_sort_order>286</children_sort_order>
<children_sort_order>262</children_sort_order>
<children_sort_order>269</children_sort_order>
<children_sort_order>279</children_sort_order>
<children_sort_order>251</children_sort_order>
<children_sort_order>299</children_sort_order>
<children_sort_order>292</children_sort_order>
<depth>1</depth>
<description/>
<name>Women's</name>
<path>products/womens-fashion-accessories</path>
<slug>womens-fashion-accessories</slug>
<state>live</state>
<status>
<state>live</state>
</status>
<updated_at>2016-07-12T03:35:17Z</updated_at>
<westfield_locale>en_AU</westfield_locale>
<sort_order>0</sort_order>
</data>
<errors />
<meta>
<api_version>1.3</api_version>
<deprecation_information />
</meta>
</categories>
I want to read the top level element and generate parent xml element then read the related category and insert as a child to first element. So the output should be like this
<Category category_id="216" name="Products" parent="0">
<Category category_id="217" name="Women's" parent="216">
</Category>
</Category>
I tried to apply recursive template with key matching but that did not work.
<xsl:key name="children-search" match="data" use="category_id"/>
<xsl:template name="Category">
<xsl:param name="parent"/>
<xsl:variable name="current" select="category_id"/>
<xsl:element name="Category">
<xsl:attribute name="id"><xsl:value-of select="category_id"/></xsl:attribute>
<xsl:attribute name="code">1</xsl:attribute><!--<xsl:value-of select="sort_order"/></xsl:attribute>--><!-- Field is no longer provided in the Westfield Category Data -->
<xsl:attribute name="name"><xsl:value-of select="slug"/></xsl:attribute>
<xsl:attribute name="displayname"><xsl:value-of select="name"/></xsl:attribute>
<xsl:attribute name="desc"><xsl:value-of select="description"/></xsl:attribute>
<xsl:attribute name="ismappable">1</xsl:attribute> <!-- Field is no longer provided in the Westfield Category Data -->
<xsl:attribute name="order"><xsl:value-of select="sort_order"/></xsl:attribute>
<xsl:attribute name="active"><xsl:choose><xsl:when test="state = 'live'">1</xsl:when><xsl:otherwise>0</xsl:otherwise></xsl:choose></xsl:attribute>
<xsl:attribute name="parent"><xsl:value-of select="$parent"/></xsl:attribute>
</xsl:element>
<!-- recursive call -->
<xsl:for-each select="children_sort_order">
<xsl:call-template name="Category"><xsl:with-param name="parent" select="key('children-search', $current)"/></xsl:call-template>
</xsl:for-each>
</xsl:template>
Please let me know if there is better way to approach this. Thanks a lot
Upvotes: 0
Views: 343
Reputation: 70638
You don't need named templates with parameters here. Instead, if you have a template that matched data
, you could then get the child elements like so:
<xsl:for-each select="children_sort_ordesr">
<xsl:apply-templates select="key('children-search', .)" />
</xsl:for-each>
Or better still (Thanks to Martin Honnen!) this..
<xsl:apply-templates select="key('children-search', children_sort_order)" />
Try this XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:key name="children-search" match="data" use="category_id"/>
<xsl:key name="parent_search" match="children_sort_order" use="."/>
<xsl:template match="categories">
<xsl:copy>
<xsl:apply-templates select="data[not(key('parent_search', category_id))]" />
</xsl:copy>
</xsl:template>
<xsl:template match="data">
<Category id="{category_id}" name="{name}">
<!-- recursive call -->
<xsl:apply-templates select="key('children-search', children_sort_order)" />
</Category>
</xsl:template>
</xsl:stylesheet>
Note the use of the "parent_search" key which is simply used to pick the top-level data
element (i.e. the data
element which has no parent). You could perhaps simplify it to <xsl:apply-templates select="data[1]" />
if the top level data
element was always the first data
element in the XML.
Also note the use of Attribute Value Templates to create the attributes on the Category
element, which simplifies the XSLT greatly.
Upvotes: 1