XSLT只有一个模板匹配?

时间:2013-02-11 18:29:16

标签: xml xslt

我仍然在使用XSLT,但我在使用XSLT模板时遇到了麻烦。我正在尝试创建一个模板来匹配我的XML数据的每个缩进级别,但出于某种原因,无论我尝试的apply-templates调用的变体是什么,我只能打印第一个缩进级别..或者更确切地说,它只应用一个缩进级别,就好像它匹配出现的第一个模式而忽略其余的模式。有人可以告诉我的XSLT语法有什么不对吗?同样的方法用于其他一些数据,并且工作正常。

<?xml version="1.0" encoding="ISO-8859-1"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" omit-xml-declaration="no" indent="yes" />
    <xsl:strip-space elements="*" />

    <xsl:template match="/">
        <config>
            <xsl:apply-templates match="/Objects/*/*" /> <!-- Matches template #1 -->
            <xsl:apply-templates match="/Objects/*/*/*" /> <!-- Matches template #2 -->
            <xsl:apply-templates match="/Objects/*/*/*/*" /> <!-- Matches template #3 -->
            <xsl:apply-templates match="/Objects/*/*/*/*/*" /> <!-- Matches template #4 -->
            <xsl:apply-templates match="/Objects/*/*/*/*/*/*" /> <!-- Matches template #5 -->
            <xsl:apply-templates match="/Objects/*/*/*/*/*/*/*" /> <!-- Matches template #6 -->
        </config>
    </xsl:template>

    <!-- <xsl:template match="Object">
        <element>
            <typefield>Object</typefield>
            <xsl:call-template name="elementPrinter" />
        </element>
    </xsl:template> -->

    <!-- Begin Template #1 -->
    <xsl:template match="Object/*">
        <element>
            <typefield>
                <xsl:value-of select="@Name" />
            </typefield>
            <xsl:call-template name="elementPrinter" />
        </element>
    </xsl:template>
    <!-- End Template #1 -->

    <!-- Begin Template #2 -->
    <xsl:template match="Object/*/*">
        <element2>
            <typefield>
                <xsl:value-of select="@Name" />
            </typefield>
            <xsl:call-template name="parentIDPrinter" />
            <xsl:call-template name="elementPrinter" />
        </element2>
    </xsl:template>
    <!-- End Template #2 -->

    <!-- Begin Template #3 -->
    <xsl:template match="Object/*/*/*">
        <element>
            <typefield>
                <xsl:value-of select="@Name" />
            </typefield>
            <xsl:call-template name="gparentIDPrinter" />
            <xsl:call-template name="parentIDPrinter" />
            <xsl:call-template name="elementPrinter" />
        </element>
    </xsl:template>
    <!-- End Template #3 -->

    <!-- Begin Template #4 -->
    <xsl:template match="Object/*/*/*/*">
        <element>
            <typefield>
                <xsl:value-of select="@Name" />
            </typefield>
            <xsl:call-template name="gparentIDPrinter" />
            <xsl:call-template name="parentIDPrinter" />
            <xsl:call-template name="elementPrinter" />
        </element>
    </xsl:template>
    <!-- End Template #4 -->

    <!-- Begin Template #5 -->
    <xsl:template match="Object/*/*/*/*/*">
        <element>
            <typefield>
                <xsl:value-of select="@Name" />
            </typefield>
            <xsl:call-template name="gparentIDPrinter" />
            <xsl:call-template name="parentIDPrinter" />
            <xsl:call-template name="elementPrinter" />
        </element>
    </xsl:template>
    <!-- End Template #5 -->

    <!-- Begin Template #6 -->
    <xsl:template match="Object/*/*/*/*/*/*">
        <element>
            <typefield>
                <xsl:value-of select="@Name" />
            </typefield>
            <xsl:call-template name="gparentIDPrinter" />
            <xsl:call-template name="parentIDPrinter" />
            <xsl:call-template name="elementPrinter" />
        </element>
    </xsl:template>
    <!-- End Template #6 -->

    <!-- Prints all elements within the matching node. -->
    <xsl:template name="elementPrinter">
        <xsl:for-each select="*">
            <xsl:if test="text() != ''">
                <xsl:choose>
                    <xsl:when test="@Name">
                        <xsl:variable name="eName">
                            <xsl:value-of select="@Name" />
                        </xsl:variable>

                        <xsl:element name="{$eName}">
                            <xsl:value-of select="text()" />
                        </xsl:element>
                    </xsl:when>
                    <xsl:when test="not(@Name)">
                        <xsl:variable name="eName">
                            <xsl:value-of select="@Type" />
                        </xsl:variable>

                        <xsl:element name="{$eName}">
                            <xsl:value-of select="text()" />
                        </xsl:element>
                    </xsl:when>
                </xsl:choose>
            </xsl:if>
        </xsl:for-each>
    </xsl:template>

    <!-- Prints a tag containing the name of the node's parent. -->
    <xsl:template name="parentIDPrinter">
        <xsl:for-each select="../../*[1]">
            <xsl:choose>
                <xsl:when test="./@Name">
                    <xsl:variable name="pName">
                        <xsl:value-of select="@Name" />
                    </xsl:variable>

                    <xsl:element name="parent">
                        <xsl:value-of select="$pName" />
                    </xsl:element>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:variable name="pName">
                        <xsl:value-of select="@Type" />
                    </xsl:variable>

                    <xsl:element name="parent">
                        <xsl:value-of select="$pName" />
                    </xsl:element>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each>
    </xsl:template>

    <!-- Prints a tag containing the name of the node's grandparent. -->
    <xsl:template name="gparentIDPrinter">
        <xsl:for-each select="../../../../*[1]">
            <xsl:choose>
                <xsl:when test="./@Name">
                    <xsl:variable name="pName">
                        <xsl:value-of select="@Name" />
                    </xsl:variable>

                    <xsl:element name="grandparent">
                        <xsl:value-of select="$pName" />
                    </xsl:element>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:variable name="pName">
                        <xsl:value-of select="@Type" />
                    </xsl:variable>

                    <xsl:element name="grandparent">
                        <xsl:value-of select="$pName" />
                    </xsl:element>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

不幸的是,我无法发布样本数据,但格式就是这样。

<Objects>
    <Object>
        <Property Name="whatever">
            <Property Name="whatever1.1">whatever</Property>
            <Property Name="whatever1.2">whatever2</Property>
        </Property>
        <Property Name="whatever">
            <Property Name="whatever1.1">whatever</Property>
            <Property Name="whatever1.2">whatever2</Property>
        </Property>
    </Object>
    <Object>
        <Property Name="whatever">
            <Property Name="whatever1.1">whatever</Property>
            <Property Name="whatever1.2">whatever2</Property>
        </Property>
        <Property Name="whatever">
            <Property Name="whatever1.1">whatever</Property>
            <Property Name="whatever1.2">whatever2</Property>
        </Property>
    </Object>
</Objects>

当我只留下第一个apply-templates调用时,它给了我第一层,我应该期待的,这是所有第一层属性标签......但如果我放入下一行,哪个应该匹配模板#2,它只是在模板1的模式后面打印完全相同的数据,而不是匹配模板2的模式数据。为什么忽略我的其他模板?

1 个答案:

答案 0 :(得分:2)

您的XSLT无效 - apply-templates具有select属性,而不是match属性。一旦修复,它会产生以下结果:

<config>
  <element>
    <typefield>whatever</typefield>
    <whatever1.1>whatever</whatever1.1>
    <whatever1.2>whatever2</whatever1.2>
  </element>
  <element>
    <typefield>whatever</typefield>
    <whatever1.1>whatever</whatever1.1>
    <whatever1.2>whatever2</whatever1.2>
  </element>
  <element>
    <typefield>whatever</typefield>
    <whatever1.1>whatever</whatever1.1>
    <whatever1.2>whatever2</whatever1.2>
  </element>
  <element>
    <typefield>whatever</typefield>
    <whatever1.1>whatever</whatever1.1>
    <whatever1.2>whatever2</whatever1.2>
  </element>
  <element2>
    <typefield>whatever1.1</typefield>
    <parent>whatever</parent>
  </element2>
  <element2>
    <typefield>whatever1.2</typefield>
    <parent>whatever</parent>
  </element2>
  <element2>
    <typefield>whatever1.1</typefield>
    <parent>whatever</parent>
  </element2>
  <element2>
    <typefield>whatever1.2</typefield>
    <parent>whatever</parent>
  </element2>
  <element2>
    <typefield>whatever1.1</typefield>
    <parent>whatever</parent>
  </element2>
  <element2>
    <typefield>whatever1.2</typefield>
    <parent>whatever</parent>
  </element2>
  <element2>
    <typefield>whatever1.1</typefield>
    <parent>whatever</parent>
  </element2>
  <element2>
    <typefield>whatever1.2</typefield>
    <parent>whatever</parent>
  </element2>
</config>

正如您在此处所见,您的第二个模板正在使用<element2>有8个实例。也许你没有注意到它们,因为它们发生在所有<element>之后。所有<elements>首先出现的原因是您首先将模板应用于所有第一级<Property>节点,然后将模板应用到下一级别。如果您希望每个节点的子节点都列在父节点之后,您应该像这样编写XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" omit-xml-declaration="no" indent="yes" />
  <xsl:strip-space elements="*" />

  <xsl:template match="/">
    <config>
      <xsl:apply-templates select="/Objects/*/*" />
      <!-- Matches template #1 -->
    </config>
  </xsl:template>

  <!-- <xsl:template match="Object">
        <element>
            <typefield>Object</typefield>
            <xsl:call-template name="elementPrinter" />
        </element>
    </xsl:template> -->

  <!-- Begin Template #1 -->
  <xsl:template match="Object/*">
    <element>
      <typefield>
        <xsl:value-of select="@Name" />
      </typefield>
      <xsl:call-template name="elementPrinter" />
    </element>
    <xsl:apply-templates select="*" />
  </xsl:template>
  <!-- End Template #1 -->

  <!-- Begin Template #2 -->
  <xsl:template match="Object/*/*">
    <element2>
      <typefield>
        <xsl:value-of select="@Name" />
      </typefield>
      <xsl:call-template name="parentIDPrinter" />
      <xsl:call-template name="elementPrinter" />
    </element2>
    <xsl:apply-templates select="*" />
  </xsl:template>
  <!-- End Template #2 -->

  <!-- Begin Template #3 -->
  <xsl:template match="Object/*/*/*">
    <element>
      <typefield>
        <xsl:value-of select="@Name" />
      </typefield>
      <xsl:call-template name="gparentIDPrinter" />
      <xsl:call-template name="parentIDPrinter" />
      <xsl:call-template name="elementPrinter" />
    </element>
    <xsl:apply-templates select="*" />
  </xsl:template>
  <!-- End Template #3 -->

  <!-- Begin Template #4 -->
  <xsl:template match="Object/*/*/*/*">
    <element>
      <typefield>
        <xsl:value-of select="@Name" />
      </typefield>
      <xsl:call-template name="gparentIDPrinter" />
      <xsl:call-template name="parentIDPrinter" />
      <xsl:call-template name="elementPrinter" />
    </element>
    <xsl:apply-templates select="*" />
  </xsl:template>
  <!-- End Template #4 -->

  <!-- Begin Template #5 -->
  <xsl:template match="Object/*/*/*/*/*">
    <element>
      <typefield>
        <xsl:value-of select="@Name" />
      </typefield>
      <xsl:call-template name="gparentIDPrinter" />
      <xsl:call-template name="parentIDPrinter" />
      <xsl:call-template name="elementPrinter" />
    </element>
    <xsl:apply-templates select="*" />
  </xsl:template>
  <!-- End Template #5 -->

  <!-- Begin Template #6 -->
  <xsl:template match="Object/*/*/*/*/*/*">
    <element>
      <typefield>
        <xsl:value-of select="@Name" />
      </typefield>
      <xsl:call-template name="gparentIDPrinter" />
      <xsl:call-template name="parentIDPrinter" />
      <xsl:call-template name="elementPrinter" />
    </element>
    <xsl:apply-templates select="*" />
  </xsl:template>
  <!-- End Template #6 -->

  <!-- Prints all elements within the matching node. -->
  <xsl:template name="elementPrinter">
    <xsl:for-each select="*">
      <xsl:if test="text() != ''">
        <xsl:choose>
          <xsl:when test="@Name">
            <xsl:variable name="eName">
              <xsl:value-of select="@Name" />
            </xsl:variable>

            <xsl:element name="{$eName}">
              <xsl:value-of select="text()" />
            </xsl:element>
          </xsl:when>
          <xsl:when test="not(@Name)">
            <xsl:variable name="eName">
              <xsl:value-of select="@Type" />
            </xsl:variable>

            <xsl:element name="{$eName}">
              <xsl:value-of select="text()" />
            </xsl:element>
          </xsl:when>
        </xsl:choose>
      </xsl:if>
    </xsl:for-each>
  </xsl:template>

  <!-- Prints a tag containing the name of the node's parent. -->
  <xsl:template name="parentIDPrinter">
    <xsl:for-each select="../../*[1]">
      <xsl:choose>
        <xsl:when test="./@Name">
          <xsl:variable name="pName">
            <xsl:value-of select="@Name" />
          </xsl:variable>

          <xsl:element name="parent">
            <xsl:value-of select="$pName" />
          </xsl:element>
        </xsl:when>
        <xsl:otherwise>
          <xsl:variable name="pName">
            <xsl:value-of select="@Type" />
          </xsl:variable>

          <xsl:element name="parent">
            <xsl:value-of select="$pName" />
          </xsl:element>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
  </xsl:template>

  <!-- Prints a tag containing the name of the node's grandparent. -->
  <xsl:template name="gparentIDPrinter">
    <xsl:for-each select="../../../../*[1]">
      <xsl:choose>
        <xsl:when test="./@Name">
          <xsl:variable name="pName">
            <xsl:value-of select="@Name" />
          </xsl:variable>

          <xsl:element name="grandparent">
            <xsl:value-of select="$pName" />
          </xsl:element>
        </xsl:when>
        <xsl:otherwise>
          <xsl:variable name="pName">
            <xsl:value-of select="@Type" />
          </xsl:variable>

          <xsl:element name="grandparent">
            <xsl:value-of select="$pName" />
          </xsl:element>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

注意我是如何在6个模板的末尾添加<xsl:apply-templates select="*" />的。我认为还有其他方法可以改进这个XSLT,但由于它似乎只是一个样本,我将把它留给另一个问题。

我认为你的逻辑在这里也被打破了:

<xsl:for-each select="../../*[1]">

在这里:

<xsl:for-each select="../../../../*[1]">

如果要切换到父母和祖父母的上下文,则应使用:

<xsl:for-each select="..">

<xsl:for-each select="../..">