在XSLT中递归应用模板的问题

时间:2015-01-09 08:24:35

标签: xml xslt xpath

我是XPath和XSLT的新手。我正在编写一个XSLT,它在输入中找到任何'complexType'作为type属性时递归地应用模板。

请注意,识别复​​杂类型的逻辑工作正常,所以我不会为此烦恼。

下面是我的XML Schema输入:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema attributeFormDefault="unqualified"
    elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:complexType name="Object1">
        <xs:all>
            <xs:element minOccurs="0" name="segment-1" type="xs:string" />
            <xs:element minOccurs="0" name="segment-2" type="xs:string" />
            <xs:element minOccurs="0" name="complexType1" type="anyComplexType" />
        </xs:all>
    </xs:complexType>
    <xs:complexType name="anyComplexType">
        <xs:all>
            <xs:element minOccurs="0" name="complexType2" type="anotherComplexType" />
        </xs:all>
    </xs:complexType>

    <xs:complexType name="anyComplexType">
        <xs:all>
            <some Element>
        </xs:all>
    </xs:complexType>
</xs:schema>

这是XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.approuter.com/schemas/cdk/api/">

    <xsl:output indent="yes" xml:space="preserve" method="xml" />

    <xsl:variable name="ObjectType" select=" 'Object1' " />
    <xsl:template match="/">
        <xsl:element name="object">
            <xsl:attribute name="name" select="$ObjectType" />
            <xsl:attribute name="label" select="$ObjectType" />
            <xsl:attribute name="minCount">1</xsl:attribute>
            <xsl:attribute name="maxCount">1</xsl:attribute>
            <xsl:apply-templates select="//*:complexType[@name = $ObjectType]" />
        </xsl:element>
    </xsl:template>
    <xsl:template match="*:complexType">
        <!-- Logic to fing complexType' goes here -->
        <xsl:call-template name="Elements" />   
    </xsl:template>
    <xsl:template name="Elements">
        <xsl:apply-templates select="//*:complexType[@name =@type]" />
    </xsl:template>
</xsl:stylesheet>

解释以下流程:

  1. XSLT开始从root读取输入。
  2. 创建对象元素,然后将具有复杂类型名称的另一个模板(ComplexTypeTemplate)应用为Object1。
  3. ComplexType模板执行一些逻辑以将complexType标识为类型属性,然后调用另一个名为“Element”的模板。
  4. 元素模板再次调用complexType模板,以便为complexType类型应用相同的逻辑。
  5. 第4步对我不起作用。我相信这里有一些XPath模式或路径问题。

1 个答案:

答案 0 :(得分:1)

您的主要问题出现在这一行:

<xsl:apply-templates select="//*:complexType[@name = @type]" />

您正在寻找其xs:complexType属性与其自己的name属性匹配的任何@type。但是,没有xs:complexType元素甚至具有type属性。

xs:element具有type属性,但当您执行xsl:apply-templates时,您位于xs:complexType元素上。调用命名模板不会改变您的上下文。

要解决此问题,您可以更改命名模板Elements以包含用于选择element元素的代码。您还需要使用current()函数来引用您当前的上下文(element而不是您要选择的complexType

<xsl:template name="Elements">
    <xsl:for-each select="*/*:element">
        <xsl:apply-templates select="//*:complexType[@name = current()/@type]" />
    </xsl:for-each>
</xsl:template>

最好不要使用命名模板,而是使用模板匹配。试试这个XSLT

试试这个XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.approuter.com/schemas/cdk/api/">

    <xsl:output indent="yes" xml:space="preserve" method="xml" />

    <xsl:variable name="ObjectType" select=" 'Object1' " />
    <xsl:template match="/">
        <xsl:element name="object">
            <xsl:attribute name="name" select="$ObjectType" />
            <xsl:attribute name="label" select="$ObjectType" />
            <xsl:attribute name="minCount">1</xsl:attribute>
            <xsl:attribute name="maxCount">1</xsl:attribute>
            <xsl:apply-templates select="//*:complexType[@name = $ObjectType]" />
        </xsl:element>
    </xsl:template>

    <xsl:template match="*:complexType">
        <xsl:value-of select="@name" />
        <xsl:apply-templates select="*/*:element" />
    </xsl:template>

    <xsl:template match="*:element">
        <xsl:apply-templates select="//*:complexType[@name = current()/@type]" />
    </xsl:template>
</xsl:stylesheet>

请注意,使用xsl:key查找complexType记录实际上可能更好。也试试这个XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.approuter.com/schemas/cdk/api/">

    <xsl:output indent="yes" xml:space="preserve" method="xml" />
    <xsl:key name="complexType" match="*:complexType" use="@name" />

    <xsl:variable name="ObjectType" select=" 'Object1' " />
    <xsl:template match="/">
        <xsl:element name="object">
            <xsl:attribute name="name" select="$ObjectType" />
            <xsl:attribute name="label" select="$ObjectType" />
            <xsl:attribute name="minCount">1</xsl:attribute>
            <xsl:attribute name="maxCount">1</xsl:attribute>
            <xsl:apply-templates select="key('complexType', $ObjectType)" />
        </xsl:element>
    </xsl:template>

    <xsl:template match="*:complexType">
        <xsl:value-of select="@name" />
        <xsl:apply-templates select="*/*:element" />
    </xsl:template>

    <xsl:template match="*:element">
        <xsl:apply-templates select="key('complexType', @type)" />
    </xsl:template>
</xsl:stylesheet>