转换后递归xsl apply-templates

时间:2017-05-09 18:08:21

标签: xml xslt recursion apply-templates

我在尝试递归应用模板时遇到了麻烦。我想说虽然我已经使用简单的XSL转换工作了几次,但我对它们并不了解。

我有以下XML表示具有方法和属性的类

<classes>
    <class name="A" author="Mr.X" >
        <attribute name="i_" type="integer" visibility="protected" />
        <attribute name="f_" type="float" visibility="private" />
        <attribute name="c_" type="char" visibility="private" />
        <method name="foo" return="integer" visibility="public" >
            <param name="a" type="integer" />
            <param name="b" type="integer" />
        </method>
    </class>

    <class name="B" author="Mr.Y" >
        <attribute name="s_" type="string" visibility="protected" />
        <method name="bar" visibility="public" />
    </class>

    <class name="CA" author="Mr.Z" base="A" >
        <attribute name="d_" type="double" visibility="protected" />
    </class>

    <class name="CB" author="Mr.Z" base="B" />

    <class name="DCA" author="Mr.X" base="CA" >
        <attribute name="s_" type="string" visibility="protected" />
    </class>
</classes>

我希望以与OO继承相同的方式获取包含具有所有属性和方法的类的XML,包括本身和基类,

我想获得以下XML

<classes>
    <class name="A" author="Mr.X" >
        <attribute name="i_" type="integer" visibility="protected" />
        <attribute name="f_" type="float" visibility="private" />
        <attribute name="c_" type="char" visibility="private" />
        <method name="foo" return="integer" visibility="public" >
            <param name="a" type="integer" />
            <param name="b" type="integer" />
        </method>
    </class>

    <class name="B" author="Mr.Y" >
        <attribute name="s_" type="string" visibility="protected" />
        <method name="bar" visibility="public" />
    </class>

    <class name="CA" author="Mr.Z" >
        <attribute name="d_" type="double" visibility="protected" />
        <!--[begin] inherited from base class A by Mr.X-->
        <attribute name="i_" type="integer" visibility="protected" />
        <attribute name="f_" type="float" visibility="private" />
        <attribute name="c_" type="char" visibility="private" />
        <method name="foo" return="integer" visibility="public" >
            <param name="a" type="integer" />
            <param name="b" type="integer" />
        </method>
        <!--[end] inherited from base class A-->
    </class>

    <class name="CB" author="Mr.Z" >
        <!--[begin] inherited from base class B by Mr.Y-->
        <attribute name="s_" type="string" visibility="protected" />
        <method name="bar" visibility="public" />
        <!--[end] inherited from base class B-->
    </class>

    <class name="DCA" author="Mr.X" >
        <attribute name="s_" type="string" visibility="protected" />
        <!--[begin] inherited from base class CA by Mr.Z-->
        <attribute name="d_" type="double" visibility="protected" />
        <!--[begin] inherited from base class A by Mr.X-->
        <attribute name="i_" type="integer" visibility="protected" />
        <attribute name="f_" type="float" visibility="private" />
        <attribute name="c_" type="char" visibility="private" />
        <method name="foo" return="integer" visibility="public" >
            <param name="a" type="integer" />
            <param name="b" type="integer" />
        </method>
        <!--[end] inherited from base class A-->
        <!--[end] inherited from base class CA-->
    </class>
</classes>

我编写了以下XSL,但只适用于一级继承。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" encoding="ISO-8859-1" indent="yes"/>

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

    <xsl:template match="/classes/import">
        <xsl:comment>importing <xsl:value-of select="@file"/> file</xsl:comment>
        <xsl:apply-templates select="document(@file)/classes/node()" />
    </xsl:template>

    <xsl:template match="*[@base]">
        <xsl:variable name="bc" select="@base" />
        <xsl:copy>
            <xsl:apply-templates select="@*[name(.)!='base']"/>                      
            <xsl:apply-templates select="/classes/class[@name=$bc]/@*[name(.)!='name' and name(.)!='author']" />
            <xsl:apply-templates /> 
            <xsl:comment>[begin] inherited from base class <xsl:value-of select="$bc"/> by <xsl:value-of select="//class[@name=$bc]/@author"/></xsl:comment>
            <xsl:apply-templates select="/classes/class[@name=$bc]/node()" />
            <xsl:comment>[end] inherited from base class <xsl:value-of select="$bc"/></xsl:comment>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

当然,如果我将上述转换应用于类所具有的最大继承级别,我(几乎)将获得所需的结果,但我的目标是仅在一次转换中实现它。

任何指南都将不胜感激。提前谢谢。

1 个答案:

答案 0 :(得分:0)

以下是解决第一个问题的方法:

XSLT 1.0

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

<xsl:key name="parent" match="class" use="@name" />

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

<xsl:template match="class">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
        <xsl:apply-templates select="key('parent', @base)" mode="inherit"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="class" mode="inherit">
    <xsl:comment>
        <xsl:text>[begin] inherited from class </xsl:text>
        <xsl:value-of select="@name"/>
    </xsl:comment>
    <xsl:copy-of select="attribute | method"/>
    <xsl:apply-templates select="key('parent', @base)" mode="inherit"/>
    <xsl:comment>
        <xsl:text>[end] inherited from class </xsl:text>
        <xsl:value-of select="@name"/>
    </xsl:comment>
</xsl:template>

</xsl:stylesheet>

应用于您的输入示例,结果将是:

<?xml version="1.0" encoding="UTF-8"?>
<classes>
  <class name="A" author="Mr.X">
    <attribute name="i_" type="integer" visibility="protected"/>
    <attribute name="f_" type="float" visibility="private"/>
    <attribute name="c_" type="char" visibility="private"/>
    <method name="foo" return="integer" visibility="public">
      <param name="a" type="integer"/>
      <param name="b" type="integer"/>
    </method>
  </class>
  <class name="B" author="Mr.Y">
    <attribute name="s_" type="string" visibility="protected"/>
    <method name="bar" visibility="public"/>
  </class>
  <class name="CA" author="Mr.Z" base="A">
    <attribute name="d_" type="double" visibility="protected"/>
    <!--[begin] inherited from class A-->
    <attribute name="i_" type="integer" visibility="protected"/>
    <attribute name="f_" type="float" visibility="private"/>
    <attribute name="c_" type="char" visibility="private"/>
    <method name="foo" return="integer" visibility="public">
      <param name="a" type="integer"/>
      <param name="b" type="integer"/>
    </method>
    <!--[end] inherited from class A-->
  </class>
  <class name="CB" author="Mr.Z" base="B">
    <!--[begin] inherited from class B-->
    <attribute name="s_" type="string" visibility="protected"/>
    <method name="bar" visibility="public"/>
    <!--[end] inherited from class B-->
  </class>
  <class name="DCA" author="Mr.X" base="CA">
    <attribute name="s_" type="string" visibility="protected"/>
    <!--[begin] inherited from class CA-->
    <attribute name="d_" type="double" visibility="protected"/>
    <!--[begin] inherited from class A-->
    <attribute name="i_" type="integer" visibility="protected"/>
    <attribute name="f_" type="float" visibility="private"/>
    <attribute name="c_" type="char" visibility="private"/>
    <method name="foo" return="integer" visibility="public">
      <param name="a" type="integer"/>
      <param name="b" type="integer"/>
    </method>
    <!--[end] inherited from class A-->
    <!--[end] inherited from class CA-->
  </class>
</classes>

我没看过你的第二个问题。