XSL Transformation with recursive elements

I have an XML with approximately the following structure, the relevant characteristic here the recursive relation of the element pair "F" and "Child_Fs". "Child_Fs" can contain any number of "F" and "F" can contain only one "Child_Fs":

<A>
    <B>
        <F id="1">
            <J/>
            <K/>
            <Child_Fs>
                <F id="1.1">
                    <J/>
                    <K/>
                    <Child_Fs>
                        <F id="1.1.1">
                            <J/>
                            <K/>
                            <Child_Fs>
                                    ...
                            </Child_Fs>
                        </F>
                        <F id="1.1.2">
                            ...
                        </F>
                        <F id="1.1.3">
                            ...
                        </F>
                        <F id="1.1.4">
                            ...
                        </F>
                        .
                        .
                        .
                    </Child_Fs>
                </F>
                <F id="1.2">
                    ...
                </F>
                <F id="1.3">
                    ...
                </F>
                <F id="1.4">
                    ...
                </F>
                .
                .
                .
            </Child_Fs>
        </F>
        <F id="2">
            ...
        </F>
        <F id="3">
            ...
        </F>
        <F id="4">
            ...
        </F>
        .
        .
        .
        <G/>
        <H/>
        <I/>
    </B>
    <C/>
    <D/>
    <E/>
</A>

My actual XML doesn't contains IDs, I just wrote them in this example for ilustration purposes.

So what I would like to get after the transformations is the following XML, in which all "F" elements are children of their corresponding highest "F/Child_Fs" ancestor. Meaning that the maximal depth for an F element should be of only two occurrances (F/Child_Fs/F/Childfs). The other important requirement here is to keep all data (attributes and text inclusive) intact, it is just a relocation operation:

<A>
    <B>
        <F id="1">
            <J/>
            <K/>
            <Child_Fs>
                <F id="1.1">
                    <J/>
                    <K/>
                    <Child_Fs>
                    </Child_Fs>
                </F>
                <F id="1.1.1">
                    <J/>
                    <K/>
                    <Child_Fs>
                    </Child_Fs>
                </F>
                ...
                <F id="1.1.2">
                    ...
                </F>
                <F id="1.1.3">
                    ...
                </F>
                <F id="1.1.4">
                    ...
                </F>
                .
                .
                .
                <F id="1.2">
                    ...
                </F>
                <F id="1.3">
                    ...
                </F>
                <F id="1.4">
                    ...
                </F>
                .
                .
                .
            </Child_Fs>
        </F>
        <F id="2">
            ...
        </F>
        <F id="3">
            ...
        </F>
        <F id="4">
            ...
        </F>
        .
        .
        .
        <G/>
        <H/>
        <I/>
    </B>
    <C/>
    <D/>
    <E/>
</A>

I would appreciate it a lot if anyone could give me a hint on this. Till now I've not been able to come up with a correct XSL Stylesheet.

Many thanks in advance.

Answers


This transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="Child_Fs[ancestor::Child_Fs]">
   <xsl:apply-templates/>
 </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document:

<A>
    <B>
        <F id="1">
            <J/>
            <K/>
            <Child_Fs>
                <F id="1.1">
                    <J/>
                    <K/>
                    <Child_Fs>
                        <F id="1.1.1">
                            <J/>
                            <K/>
                            <Child_Fs>
                                    ...
                            </Child_Fs>
                        </F>
                        <F id="1.1.2">
                            ...
                        </F>
                        <F id="1.1.3">
                            ...
                        </F>
                        <F id="1.1.4">
                            ...
                        </F>
                        .
                        .
                        .
                    </Child_Fs>
                </F>
                <F id="1.2">
                    ...
                </F>
                <F id="1.3">
                    ...
                </F>
                <F id="1.4">
                    ...
                </F>
                .
                .
                .
            </Child_Fs>
        </F>
        <F id="2">
            ...
        </F>
        <F id="3">
            ...
        </F>
        <F id="4">
            ...
        </F>
        .
        .
        .
        <G/>
        <H/>
        <I/>
    </B>
    <C/>
    <D/>
    <E/>
</A>

produces the wanted, correct result:

<A>
   <B>
      <F id="1">
         <J/>
         <K/>
         <Child_Fs>
            <F id="1.1">
               <J/>
               <K/>
               <F id="1.1.1">
                  <J/>
                  <K/>
                                        ...
                                </F>
               <F id="1.1.2">
                                ...
                            </F>
               <F id="1.1.3">
                                ...
                            </F>
               <F id="1.1.4">
                                ...
                            </F>
                            .
                            .
                            .
                        </F>
            <F id="1.2">
                        ...
                    </F>
            <F id="1.3">
                        ...
                    </F>
            <F id="1.4">
                        ...
                    </F>
                    .
                    .
                    .
                </Child_Fs>
      </F>
      <F id="2">
                ...
            </F>
      <F id="3">
                ...
            </F>
      <F id="4">
                ...
            </F>
            .
            .
            .
            <G/>
      <H/>
      <I/>
   </B>
   <C/>
   <D/>
   <E/>
</A>

Explanation:

Proper use and overriding of the identity rule.


As long as the structure you describes holds in place, you can use a fairly simple algorithm as described below. If the structure becomes more free-form then it becomes a harder problem.

Algorithm

Child_Fs with exactly 1 ancestor F:

  • These are recipients. They will pull in all descendant F

Child_Fs with more than 1 ancestor F:

  • These are donors. Copy other children but exclude F children

d

<xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:xi="http://www.w3.org/2001/XInclude"
      exclude-result-prefixes="xsl xi">
 <xsl:output method="xml" indent="yes"/>
 <xsl:strip-space elements="*" />

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="Child_Fs[count(ancestor::F)=1]">
 <!-- Child_F which is recipient of all Fs. -->
 <xsl:copy>
  <xsl:apply-templates select="@* | node() | //F" />
 </xsl:copy>
</xsl:template> 

<xsl:template match="Child_Fs[count(ancestor::F) &gt; 1]">
 <!-- Child_F which is donor of Fs. -->
 <xsl:copy>
  <xsl:apply-templates select="@* | node()[not(self::F)]" />
 </xsl:copy>
</xsl:template>

</xsl:stylesheet> 

Need Your Help

How to configure zookeeper, kafka and storm in ubuntu 14.04?

apache-kafka apache-storm apache-zookeeper

I want to clear steps of how to install zookeeper, kafka and storm in Ubuntu