xml - XSLT 1.0 build hierarchy from parent-child relationship -


i have following flat xml structure.

<customui >   <elements>     <tab id="1" parent="0"/>     <tab id="-1" parent="0"/>     <group id="-2"  parent="-1"/>     <group id="2"  parent="1"/>     <group id="11"  parent="1"/>     <menu id="-27"  parent="-26"/>     <menu id="-24" parent="-4"/>     <menu id="-18" parent="-4"/>     <menu id="-11"  parent="-9"/>     <menu id="-10" parent="-9"/>     <menu id="-3"  parent="-2"/>     <menu id="3"  parent="2"/>     <menu id="10" parent="65"/>     <menu id="12"  parent="11"/>     <menu id="16"  parent="11"/>     <menu id="18" parent="11"/>     <menu id="25" parent="11" />     <menu id="29" parent="11"/>     <menu id="46" parent="11"/>     <menu id="74" parent="-3"/>     <menu id="85" parent="11"/>     <menu id="89" parent="2"/>     <menu id="95" parent="2"/>     <menu id="104"  parent="2"/>     <button id="-28"  parent="-2"/>     <button id="-25" parent="-24"/>     <button id="-12" parent="-11"/>     <button id="32" parent="29"/>     <button id="26" parent="25"/>     <button id="41" parent="18"/>     <button id="66" parent="46"/>     <button id="82"  parent="74"/>     <button id="86" parent="46"/>     <button id="87"  parent="89"/>     <button id="90"  parent="89"/>     <button id="99"  parent="89"/>     <button id="58"  parent="16"/>     <button id="42" parent="18"/>     <button id="47"  parent="46"/>     <button id="48"  parent="46"/>     <button id="33" parent="29"/>     <!-- list continues -->   </elements> </customui> 

what build hierarchy using relationship between 'id' value , 'parent' value.

<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform">  <xsl:template match="@*|node()" name="identity">     <xsl:copy>        <xsl:apply-templates select="@*|node()"/>     </xsl:copy> </xsl:template>  <xsl:template match="tab">     <xsl:variable name="controllerid" select="@id" as="xs:string"/>     <xsl:copy>         <xsl:apply-templates select="@*|node()"/>         <xsl:copy-of select="//*[@parent = $controllerid]"/>     </xsl:copy> </xsl:template>   <xsl:template match="group" name="group">     <xsl:variable name="controllerid" select="@id" as="xs:string"/>     <xsl:copy>        <xsl:apply-templates select="@*|node()"/>        <xsl:copy-of select="//*[@parent = $controllerid]"/>     </xsl:copy> </xsl:template>   <xsl:template match="menu" name="menu">     <xsl:variable name="controllerid" select="@id" as="xs:string"/>     <xsl:copy>        <xsl:apply-templates select="@*|node()"/>        <xsl:copy-of select="//*[@parent = $controllerid]"/>     </xsl:copy> </xsl:template>  </xsl:stylesheet> 

this have tried until not work.

any appreciated.

this bit crude, should work:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform">   <!-- identity template -->   <xsl:template match="@* | node()">     <xsl:copy>       <xsl:apply-templates select="@* | node()"/>     </xsl:copy>   </xsl:template>    <xsl:template match="elements">     <xsl:copy>       <xsl:for-each select="*">         <xsl:if test="not(../*[@id=current()/@parent])">           <xsl:apply-templates select="."/>         </xsl:if>       </xsl:for-each>     </xsl:copy>   </xsl:template>    <xsl:template match="elements/*">     <xsl:copy>       <xsl:apply-templates select="@* | node()"/>       <xsl:apply-templates select="../*[@parent = current()/@id]"/>     </xsl:copy>   </xsl:template> </xsl:stylesheet> 

the elements template copies it, each element within it, applies templates if there no other sibling who's parent one; i.e. if data represents complete hierarchy, it'll root.

the second template applies in elements template, , copies as-is, includes other elements who's parent current one, recursively.

an alternative using keys might faster, have problems if there's more 1 elements element:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform">   <xsl:key name="elemsbyid" match="elements/*" use="@id"/>   <xsl:key name="elemsbyparent" match="elements/*" use="@parent"/>    <xsl:template match="@* | node()">     <xsl:copy>       <xsl:apply-templates select="@* | node()"/>     </xsl:copy>   </xsl:template>    <xsl:template match="elements">     <xsl:copy>       <xsl:apply-templates select="*[not(key('elemsbyid',@parent))]"/>     </xsl:copy>   </xsl:template>    <xsl:template match="elements/*">     <xsl:copy>       <xsl:apply-templates select="@* | node()"/>       <xsl:apply-templates select="key('elemsbyparent',@id)"/>     </xsl:copy>   </xsl:template> </xsl:stylesheet> 

Comments

Popular posts from this blog

c - How to retrieve a variable from the Apache configuration inside the module? -

c# - Constructor arguments cannot be passed for interface mocks -

python - malformed header from script index.py Bad header -