外部数据中的XSL apply-template

时间:2017-05-16 12:45:28

标签: xml xslt external apply-templates

我想转换一个表示类及其基类的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文件中定义,与其他文件与import元素链接,这意味着可以像使用外部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非常相似,但添加了以下模式,以便处理新元素

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

与import元素相关联的转换适用于外部文件中定义的类,但基类继承行为不适用于这些类。

上述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文件中定义的类生成密钥。第二个是应用“继承”模式谓词,但我再次失败,因为我不知道外部文件名,以便为所有文件应用具有继承模式的模板类。

关于如何从外部数据中为类应用“继承”模板的任何帮助都将非常感激。任何方法,无论有没有钥匙,都适合我。

提前致谢。

1 个答案:

答案 0 :(得分: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]

相关问题