0

我仍然对 XSLT 感到困惑,而且我在使用 XSLT 模板时遇到了麻烦。我正在尝试制作一个模板来匹配我的 XML 数据的每个缩进级别,但由于某种原因,无论我尝试应用模板调用的哪种变体,我都只能打印第一个缩进级别。 . 或者更确切地说,它只应用一个缩进级别,就好像它匹配出现的第一个模式并忽略其余部分。有人可以判断我的 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 的模式数据。为什么它忽略了我的其他模板?

4

1 回答 1

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>

正如您在此处看到的,正在使用您的第二个模板。有 8 个实例<element2>。也许您没有注意到它们,因为它们发生在所有<element>s. 所有先出现的原因<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>

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

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

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

和这里:

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

如果你想切换到父母和祖父母的上下文,你应该使用:

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

<xsl:for-each select="../..">
于 2013-02-11T18:54:32.993 回答