我想转换一个表示类及其基类的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文件中定义的类生成密钥。第二个是应用“继承”模式谓词,但我再次失败,因为我不知道外部文件名,以便为所有文件应用具有继承模式的模板类。
关于如何从外部数据中为类应用“继承”模板的任何帮助都将非常感激。任何方法,无论有没有钥匙,都适合我。
提前致谢。
答案 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]
。