xml - XSLT to wrap all chid elements in parent tag -
i have xml document this:
<catalogs> <catalog> <code>x</code> <name>ox</name> <categories> <category> <id>9245</id> <name>a</name> <category> <id>9247</id> <name>x</name> </category> </category> <category> <id>9250</id> <name>x</name> <category> <id>9252</id> <name>x</name> </category> <category> <id>9258</id> <name>x</name> <category> <id>9260</id> <name>x</name> </category> <category> <id>9261</id> <name>x</name> </category> <category> <id>9261</id> <name>x</name> </category> </category> </category> <category> <id>9251</id> <name>x</name> <category> <id>9253</id> <name>x</name> </category> </category> </categories> </catalog> </catalogs>
i wrap each subset of category-tags collection tag (categories). problem here recursive tree, , depth of tree unknown.
i tried use xslt transformation this, haven't succeeded yet. attempt
<?xml version="1.0" encoding="iso-8859-1"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform"> <xsl:template match="category"> <categories><xsl:apply-templates select="category"/></categories> </xsl:template> </xsl:stylesheet>
just replaces children empty categories tag.
sample output should this:
<catalogs> <catalog> <code>x</code> <name>ox</name> <categories> <category> <id>9245</id> <name>a</name> <categories> <category> <id>9247</id> <name>x</name> </category> </categories> </category> <category> <id>9250</id> <name>x</name> <categories> <category> <id>9252</id> <name>x</name> </category> <category> <id>9258</id> <name>x</name> <categories> <category> <id>9260</id> <name>x</name> </category> <category> <id>9261</id> <name>x</name> </category> <category> <id>9261</id> <name>x</name> </category> </categories> </category> </categories> </category> <category> <id>9251</id> <name>x</name> <categories> <category> <id>9253</id> <name>x</name> </category> </categories> </category> </categories> </catalog> </catalogs>
any pointers (or full solutions) appreciated.
to start with, should building xslt on top of xslt identity template, copy nodes in xml don't have explicit matching templates
<xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template>
without this, xslt's built-in templates kick-in, , output text of element finds.
the other problem xslt, when match category element, doing <xsl:apply-templates select="category"/>
means telling xslt category elements children of current element.
one approach taking have template match parent of category element (excluding categories elements already)
<xsl:template match="*[not(self::categories)][category]">
then, within this, can copy element, , insert categories element within contain category elements
<xsl:copy> <xsl:apply-templates select="@*|node()[not(self::category)]"/> <categories> <xsl:apply-templates select="category"/> </categories> </xsl:copy>
here full xslt in case
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform"> <xsl:output method="xml" indent="yes"/> <xsl:template match="*[not(self::categories)][category]"> <xsl:copy> <xsl:apply-templates select="@*|node()[not(self::category)]"/> <categories> <xsl:apply-templates select="category"/> </categories> </xsl:copy> </xsl:template> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
a disadvantage of approach though if elements occur after category within parent, these moved before categories element gets created.
another approach match first occurence of category element within parent, , copy element , following siblings
try xslt too
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform"> <xsl:output method="xml" indent="yes"/> <xsl:template match="category[1]"> <categories> <xsl:apply-templates select="self::*|following-sibling::category" mode="categories"/> </categories> </xsl:template> <xsl:template match="category" mode="categories"> <xsl:call-template name="identity" /> </xsl:template> <xsl:template match="category" /> <xsl:template match="@*|node()" name="identity"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
two things note approach. firstly, xslt give priority more specific template match, when looking templates match node. "category[1]" used on "category" first child category element.
secondly, note use of mode here, because otherwise have 2 templates match "category" same priority, not allowed.
Comments
Post a Comment