2011-08-12 95 views
2

我試圖找到一種方法來索引包含特定類型的子節點的節點,並讓它們從每找到一個子節點就會增加一個。我嘗試使用count(),但是這顯示了我的代碼中節點的位置,而不是找到的子節點的索引。在其他語言中,我會使用一個變量,但這不是XSLT中的一個選項。
我已經閱讀了使用模板的遞歸計數的一些示例,但是我不熟悉XSLT將其集成到我現有的代碼中。如何索引/計數包含子節點的節點,格式爲1,2,3,4 4

XML

<?xml version="1.0" encoding="UTF-8"?> 
<entry> 
     <node> 
      <subnodeA>test_subnodeA1</subnodeA> 
      <subnodeB>test_subnodeB1</subnodeB> 
     </node> 
     <node> 
      <subnodeA>test_subnodeA2</subnodeA> 
      <subnodeB>test_subnodeB2</subnodeB> 
     </node> 
     <node> 
      <subnodeA>test_subnodeA3</subnodeA> 
     </node> 
     <node> 
      <subnodeA>test_subnodeA4</subnodeA> 
      <subnodeB>test_subnodeB3</subnodeB> 
     </node> 
</entry> 

XSLT

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
<xsl:template match="/"> 

    <!-- Initial usage --> 
    <xsl:for-each select="node"> 
     <xsl:value-of select="subnodeA"/> 
      <xsl:if test="subnodeB != ''"> 
       <xsl:value-of select="position()"/> 
      </xsl:if> 
    </xsl:for-each> 

    <!-- Second usage --> 
    <xsl:for-each select="node"> 
     <xsl:if test="subnodeB != ''"> 
      <xsl:value-of select="position()"/>. 
      <xsl:value-of select="subnodeB"/> 
     </xsl:if> 
    </xsl:for-each> 

</xsl:template> 

我想用我的方法來顯示類似

test_subnodeA1 1 
test_subnodeA2 2 
test_subnodeA3 
test_subnodeA4 3 

1 test_subnodeB1 
2 test_subnodeB2 
3 test_subnodeB3 

但我只能得到

test_subnodeA1 1 
test_subnodeA2 2 
test_subnodeA3 
test_subnodeA4 4 

1 test_subnodeB1 
2 test_subnodeB2 
4 test_subnodeB3 

某些條目有沒有subnodeB,然後用一個節點的幾個節點,所以我的名單開始在3,4或5

+0

好問題,+1。根據我的答案,最簡單的解決方案根本不需要任何明確的條件邏輯和任何特殊的軸/函數。 –

+0

@empo注意到,我最初並沒有正確理解這個問題。從那時起我糾正了我的答案,現在解決方案是正確的,仍然不涉及任何明確的條件,軸,'xsl:for-each'。 –

回答

1

在第一種情況下,你可以通過前面的計算得到的位置兄弟姐妹

<xsl:value-of select="count(preceding-sibling::node[subnodeA and subnodeB]) + 1" /> 

在第二種情況下,你只是想節點元素與subnodeB

<xsl:for-each select="node[subnodeA and subnodeB]"> 

以下是示例XSLT。請注意,我已經使用XSL轉換:對,每個使用XSL:申請模板

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text"/> 

    <xsl:template match="/entry"> 
     <xsl:apply-templates select="node" mode="initial" /> 
     <xsl:apply-templates select="node[subnodeB]" mode="second" /> 
    </xsl:template> 

    <xsl:template match="node" mode="initial"> 
     <xsl:value-of select="subnodeA" /> 
     <xsl:if test="subnodeB != ''"> 
     <xsl:text> - </xsl:text><xsl:value-of select="count(preceding-sibling::node[subnodeA and subnodeB]) + 1" /> 
     </xsl:if> 
     <xsl:text>&#13;</xsl:text> 
    </xsl:template> 

    <xsl:template match="node" mode="second"> 
     <xsl:value-of select="position()" /> - <xsl:value-of select="subnodeB" /> 
     <xsl:text>&#13;</xsl:text> 
    </xsl:template> 
</xsl:stylesheet> 

這將生成以下文本輸出

test_subnodeA1 - 1 
test_subnodeA2 - 2 
test_subnodeA3 
test_subnodeA4 - 3 
1 - test_subnodeB1 
2 - test_subnodeB2 
3 - test_subnodeB3 
+0

不錯的入門+1!你可以在某處使用'concat()'。 –

+0

使用上面的例子,這個對我來說很好,我能理解發生了什麼 - 謝謝。我確實需要修改「第二個」模板,以便在更復雜的情況下使用: \t \t \t的 - 的 \t '你把我放在正確的軌道上。 – Scottmeup

0

我們可以使用計數也應用模板直接在感興趣的節點上:

鑑於子節點A作爲當前節點:

  • count(preceding::subnodeB[not(../subnodeA)])計數之前的所有節點,而不subnodeA(電流偏移)
  • count(preceding::subnodeA[../subnodeB])計數之前的所有節點與subnodeB(相對位置 - 1)

讓我們來看看如何將其與重複工作(僅子部分A,因爲子部分B是微不足道的):

<xsl:template match="entry"> 

    <xsl:for-each select="node/subnodeA"> 
     <xsl:value-of select="."/> 
     <xsl:if test="../subnodeB"> 
      <xsl:value-of select=" 
       count(preceding::subnodeB[not(../subnodeA)]) 
       + count(preceding::subnodeA[../subnodeB]) 
       + 1 "/> 
     </xsl:if> 
     <xsl:if test="position()!=last()"> 
      <xsl:value-of select="'&#xA;'"/> 
     </xsl:if> 
    </xsl:for-each> 

</xsl:template> 

和與應用模板:

<xsl:template match="entry"> 
    <xsl:apply-templates select="node/subnodeA"/> 
</xsl:template> 

<xsl:template match="node/subnodeA"> 
    <xsl:value-of select="."/> 
    <xsl:if test="../subnodeB"> 
     <xsl:value-of select=" 
      count(preceding::subnodeB[not(../subnodeA)]) 
      + count(preceding::subnodeA[../subnodeB]) 
      + 1 "/> 
    </xsl:if> 
    <xsl:if test="position()!=last()"> 
     <xsl:value-of select="'&#xA;'"/> 
    </xsl:if> 
</xsl:template> 
0

這可能是最簡單的解決方案之一 - 無xsl:for-each,沒有count(),沒有特殊的軸,並在所有沒有明確的條件邏輯:

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:template match="/"> 
     <xsl:apply-templates select="*/node/subnodeA"/> 
     <xsl:apply-templates select="*/node/subnodeB"/> 
    </xsl:template> 

    <xsl:template match="*[subnodeB]/subnodeA"> 
     <xsl:value-of select="concat(., ' ')"/> 
     <xsl:number level="any" count="*[subnodeB]/subnodeA"/> 
     <xsl:text>&#xA;</xsl:text> 
    </xsl:template> 

    <xsl:template match="subnodeB"> 
     <xsl:value-of select="concat(position(), ' ', ., '&#xA;')"/> 
    </xsl:template> 

    <xsl:template match="text()"> 
     <xsl:value-of select="concat(., '&#xA;')"/> 
    </xsl:template> 
</xsl:stylesheet> 

應用時在提供的XML文檔上

<entry> 
    <node> 
     <subnodeA>test_subnodeA1</subnodeA> 
     <subnodeB>test_subnodeB1</subnodeB> 
    </node> 
    <node> 
     <subnodeA>test_subnodeA2</subnodeA> 
     <subnodeB>test_subnodeB2</subnodeB> 
    </node> 
    <node> 
     <subnodeA>test_subnodeA3</subnodeA> 
    </node> 
    <node> 
     <subnodeA>test_subnodeA4</subnodeA> 
     <subnodeB>test_subnodeB3</subnodeB> 
    </node> 
</entry> 

想要的,正確的結果產生

test_subnodeA1 1 
test_subnodeA2 2 
test_subnodeA3 
test_subnodeA4 3 
1 test_subnodeB1 
2 test_subnodeB2 
3 test_subnodeB3 
+0

其他答案不那麼簡單的原因是因爲他們管理的事實是,子節點A的計數不是位置的,必須按照OP的要求進行計算。 –

+0

@empo:是的,今天早上我還在睡覺,謝謝你讓我醒來。 :)。我現在編輯了我的答案,以提供一個正確而且仍然最簡單的解決方案。 –

+0

感謝您的回覆 - 這真的讓我看到了XSLT可以實現的目標。我在這個級別工作之前還有一段時間;) – Scottmeup

相關問題