0

我想转换一个表示类及其基类的 XML,其中类包括它自己的方法和属性,以及它的所有基类的方法和属性,因为 OO 继承有效。

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

应该转化为

<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 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 class A-->
  </class>
  <class name="CB" author="Mr.Z">
    <!--[begin] inherited from class B by Mr.Y-->
    <attribute name="s_" type="string" visibility="protected"/>
    <method name="bar" visibility="public"/>
    <!--[end] inherited from class B-->
  </class>
  <class name="DCA" author="Mr.X">
    <attribute name="s_" type="string" visibility="protected"/>
    <!--[begin] inherited from class CA by Mr.Z-->
    <attribute name="d_" type="double" visibility="protected"/>
    <!--[begin] inherited from 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 class A-->
    <!--[end] inherited from class CA-->
  </class>
</classes>

在Michael的帮助下,如果所有类都定义在同一个 XML 文件中,那么我有以下 XSL 可以正常工作。

<?xml version="1.0" encoding="UTF-8"?>
<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: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="@*[name()!='base']|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:text> by </xsl:text>
            <xsl:value-of select="@author"/>
        </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"?>
<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:strip-space elements="*"/>

    <!-- 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="@*[name()!='base']|node()"/>
            <xsl:apply-templates select="//class[@name=current()/@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:text> by </xsl:text>
            <xsl:value-of select="@author"/>
        </xsl:comment>
        <xsl:copy-of select="attribute | method"/>
        <xsl:apply-templates select="//class[@name=current()/@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 或其他 XML 文件中定义,并通过导入元素与其他文件链接,这意味着外部 XML 可以像编写一样使用在主 XML 中。

表示这些类的简化 XML 可以是

<classes>    
    <import file="c2.xml" />

    <class name="XZ" author="Mr.B" base="Z">
        <method name="foo" visibility="public" />
    </class>
</classes>

c2.xml 的内容可能是

<classes>
    <class name="Z" author="Mr.A" >
        <attribute name="i_" type="integer" visibility="protected" />
    </class> 
</classes>

并且预期的输出将是

<classes>
  <class name="Z" author="Mr.A">
    <attribute name="i_" type="integer" visibility="protected"/>
  </class>
  <class name="XZ" author="Mr.B">
    <method name="foo" visibility="public"/>
    <!--[begin] inherited from class Z by Mr.A-->
    <attribute name="i_" type="integer" visibility="protected"/>
    <!--[end] inherited from class Z-->
  </class>
</classes>

新的 XSL 与上面的非常相似,但添加了以下模式,以处理新元素

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

因此,使用键时 XSL 将如下所示

<?xml version="1.0" encoding="UTF-8"?>
<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: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="/classes/import">
        <xsl:comment>
            <xsl:text>importing </xsl:text>
            <xsl:value-of select="@file"/>
            <xsl:text> file</xsl:text>
        </xsl:comment>
        <xsl:apply-templates select="document(@file)/classes/node()" /> 
    </xsl:template>  

    <xsl:template match="class">
        <xsl:copy>
            <xsl:apply-templates select="@*[name()!='base']|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:text> by </xsl:text>
            <xsl:value-of select="@author"/>
        </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"?>
<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:strip-space elements="*"/>

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

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

    <xsl:template match="class">
        <xsl:copy>
            <xsl:apply-templates select="@*[name()!='base']|node()"/>
            <xsl:apply-templates select="//class[@name=current()/@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:text> by </xsl:text>
            <xsl:value-of select="@author"/>
        </xsl:comment>
        <xsl:copy-of select="attribute | method"/>
        <xsl:apply-templates select="//class[@name=current()/@base]" mode="inherit"/>
        <xsl:comment>
            <xsl:text>[end] inherited from class </xsl:text>
            <xsl:value-of select="@name"/>
        </xsl:comment>
    </xsl:template>

</xsl:stylesheet>

与导入元素相关的转换对于外部文件中定义的类可以正常工作,但基类继承行为不适用于这些类。

上述 XSL 和前一个 XML(包含 c2.xml 文件的那个)的(错误)输出是

<classes>
  <!--importing c2.xml file-->
  <class name="Z" author="Mr.A">
    <attribute name="i_" type="integer" visibility="protected"/>
  </class>
  <class name="XZ" author="Mr.B">
    <method name="foo" visibility="public"/>
  </class>
</classes>

请注意,XZ 类不包括来自其基类 Z 的方法和属性

请注意,外部 xml 文件也可能包含导入元素

我尝试了两种不同的方法。第一个是使用类的键,包括那些在外部 XML 文件中声明的键。我失败了,因为我事先不知道外部文件名,以便为这些外部 XML 文件中定义的类生成密钥。第二个是应用“继承”模式谓词,但我再次失败了,因为我不知道外部文件名,以便为所有文件应用具有继承模式的模板类。

任何有关如何从外部数据为类应用“继承”模板的帮助,将不胜感激。任何方法,有或没有钥匙,对我来说都很好。

提前致谢。

4

1 回答 1

0

密钥仅在单个文档中有效。我建议两种方法:

(a) 首先将所有文档合并为一个,然后使用您当前的解决方案。

(b) 不使用键,而是以 XSLT 3.0 映射的形式构建跨文档索引。像这样的东西:

<xsl:mode name="index" on-no-match="shallow-skip"/>

<xsl:variable name="globalIndex" as="map(xs:string, element(*))">
  <xsl:map>
    <xsl:apply-templates mode="index"/>
  </xsl:map>
</xsl:variable>

<xsl:template match="class" mode="index">
  <xsl:map-entry key="@name" select="."/>
  <xsl:apply-templates mode="index"/>
</xsl:template>

<xsl:template match="import" mode="index">
  <xsl:apply-templates select="doc(@file)" mode="index"/>
</xsl:template>

然后你以前用过的地方key('parent', @base),现在就可以用了$globalIndex(@base)

(c) 此解决方案不会为您提供键或映射的速度,除非您的处理器具有自动索引事物的智能优化器(如 Saxon-EE);但它只使用 XSLT 2.0:

<xsl:variable name="allClasses" as="element(class)*">
    <xsl:apply-templates mode="index"/>
</xsl:variable>

<xsl:template match="class" mode="index">
  <xsl:sequence select="."/>
  <xsl:apply-templates mode="index"/>
</xsl:template>

<xsl:template match="import" mode="index">
  <xsl:apply-templates select="doc(@file)" mode="index"/>
</xsl:template>

<xsl:template match="node()" mode="index">
  <xsl:apply-templates mode="index"/>
</xsl:template>

然后你以前用过的地方key('parent', @base),现在就可以用了$allClasses[@name=current()/@base]

于 2017-05-16T15:18:08.697 回答