使用递归元素的XSL转换

时间:2012-07-16 19:55:01

标签: xml xslt recursion transformation

我有一个大约具有以下结构的XML,这里的相关特征是元素对“F”和“Child_Fs”的递归关系。 “Child_Fs”可以包含任意数量的“F”,“F”只能包含一个“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>

我的实际XML不包含ID,我只是在这个例子中写了它们用于ilustration目的。

因此,我希望在转换之后获得以下XML,其中所有“F”元素都是其对应的最高“F / Child_Fs”祖先的子元素。这意味着F元素的最大深度应该只有两个出现(F / Child_Fs / F / Childfs)。这里另一个重要的要求是保持所有数据(属性和文本包含)完整,它只是一个重定位操作:

<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>

如果有人能给我一个暗示,我会非常感激。直到现在我还没有能够提出正确的XSL样式表。

非常感谢提前。

2 个答案:

答案 0 :(得分:0)

此转化

<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>

应用于提供的XML文档时:

<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>

会产生想要的正确结果:

<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>

<强>解释

正确使用和覆盖 identity rule

答案 1 :(得分:0)

只要您描述的结构保持不变,就可以使用如下所述的相当简单的算法。如果结构变得更加自由,那么它将成为一个更难的问题。

算法

Child_Fs恰好有1个祖先F:

  • 这些是收件人。他们将拉入所有后代F

具有超过1个祖先F的Child_Fs:

  • 这些是捐助者。复制其他孩子但不包括F孩子

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>