Xml XSL在外部数据中应用模板
我想转换一个表示类及其基类的XML,其中的类包括它自己的方法和属性,以及它所有基类的方法和属性,就像OO继承一样 这方面的XML可以是Xml XSL在外部数据中应用模板,xml,xslt,external,apply-templates,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" vi
<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="Z" author="Mr.A" >
<attribute name="i_" type="integer" visibility="protected" />
</class>
</classes>
,我有以下XSL,如果所有类都在同一个XML文件中定义,那么它可以正常工作
<?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>
[开始]从类继承
通过
[end]从类继承
或以下等效但没有键的转换
<?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>
[开始]从类继承
通过
[end]从类继承
现在,我想处理的是,这些类可以在主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="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="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>
进口
文件
[开始]从类继承
通过
[end]从类继承
或者像下面的一样,不使用钥匙
<?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>
进口
文件
[开始]从类继承
通过
[end]从类继承
对于外部文件中定义的类,与导入元素关联的转换可以正常工作,但基类继承行为不适用于这些类
上述XSL和以前的XML(包含c2.XML文件的XML)的(错误)输出为
请注意,XZ类不包括基类Z中的方法和属性
请注意,外部xml文件也可能包含导入元素
<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>
我尝试了两种不同的方法。第一种方法是为类使用键,包括那些在外部XML文件中声明的类。我失败了,因为我事先不知道外部文件名,以便为这些外部XML文件中定义的类生成密钥。第二个是应用“inherit”模式谓词,但我还是失败了,因为我不知道外部文件名,无法为所有这些文件应用带有inherit模式的模板类
关于如何从外部数据为类应用“继承”模板的任何帮助,都将不胜感激。任何方法,不管有没有钥匙,都适合我
提前感谢。键只能在单个文档中使用。我建议两种方法:
(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>
然后在您以前使用的键('parent',@base)
,现在您可以使用$allClasses[@name=current()/@base]
非常感谢您的及时回复。如果不使用钥匙,可能实现这一点吗?性能不是一个问题,因为XML不是那么大,所以使用非键方法可能是可行的。如果没有,我将采用你建议的第一种方法。再次感谢您抽出时间。当做Hern您可以使用类似的方法创建一个全局变量,其中包含(引用)所有文档中的所有类元素,然后使用筛选器表达式查找包含所需名称的类。请您详细说明一下上述选项好吗?。据我所知,变量是在应用模板模式之前加载的,它们的值不能修改或更新。因此,我应该提前知道外部XML文件,但事实并非如此,因为要查找的文件是XML本身的信息。我应该使用什么最低XSL版本来实现这一点?我更喜欢使用1.0版,但这不是一个要求。我扩展了选项(c)。如果您想要XSLT1.0解决方案,您可能必须使用选项(a),但我不会为您扩展它——我上一次使用1.0是在大约15年前的愤怒中,我已经忘记了克服其局限性的所有技巧。