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

Popular posts from this blog

basic authentication with http post params android -

vb.net - Virtual Keyboard commands -

css - Firefox for ubuntu renders wrong colors -