2013-02-11 124 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