2013-02-11 72 views
0

我仍然在用XSLT耳熟能详,而且我在XSLT模板上遇到了麻烦。我试图创建一个模板来匹配我的XML数据的每个缩进级别,但出于某种原因,无论我尝试使用什么样的apply-templates调用,我只能打印第一个缩进级别..或者说,它只应用一个缩进级别,就好像它匹配出现的第一个模式,而忽略其余的模式。有人可以告诉我有关XSLT语法的任何内容吗?同样的方法用于其他一些数据,并且工作得很好。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> 

当我离开只是第一个应用模板调用,它给我的第一层,这是我应该想到,这是所有的第一层属性标记......但如果我把在未来行,它应该匹配模板#2,它所做的只是在模板1的模式之后打印完全相同的数据,而不是匹配模板2的模式数据。为什么它忽略了我的其他模板?

回答

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>之后。所有<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=".."> 

and

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

我几乎只是复制元素和parentID打印机的一些遗留代码,所以我不确定这些,但是到目前为止,我已经得到了正确的父母...... – 2013-02-11 19:49:10

+0

@DarinBeaudreau'。 ./../* [1]'将选择上下文节点的祖父母的第一个孩子。在某些情况下,这与上下文节点的父节点是相同的,但在大多数情况下不是。我上面的其他信息是否清除了您的困惑? – JLRishe 2013-02-11 21:01:59

+0

是的,我不知道为什么我会在apply-templates调用中使用“匹配”...有时我会混淆属性,但我认为我已经明白了。至于祖父母/父母XPath ...它工作正常,所以我不明白问题在哪。 – 2013-02-11 21:55:52