2011-08-11 47 views
3

我正在尋找一種將某些特定的後代重新排列爲其祖先節點級別的一般方法。XSLT 1.0將具體的子孫筆記重新排列到父母/祖先的相同級別

什麼是重要的:

  • 我需要它適用於px一個通用模板。
  • 節點a b DEEPSPACENODE(從上到下)的順序不應該儘可能地改變。

我輸入:

<root> 
    <p> 
     <a>1</a> 
     <a>2</a> 
     <a><DEEPSPACENODE/></a> 
     <b>3</b> 
     <b>4</b> 
     <a>5</a> 
     <a>6</a> 
     <b>7</b> 
    </p> 

    <x> 
     <a>8</a> 
     <a>9</a> 
     <b>10</b> 
     <b>11</b> 
     <a>12</a> 
     <a>13</a> 
     <b>14</b> 
    </x>  
</root> 

我想要的輸出:

<root> 
    <p> 
     <a>1</a> 
     <a>2</a> 
     <a/> 
    </p> 
    <DEEPSPACENODE/> 
    <b>3</b> 
    <b>4</b> 
    <p> 
     <a>5</a> 
     <a>6</a> 
    </p> 
    <b>7</b> 

    <x> 
     <a>8</a> 
     <a>9</a> 
    </x> 
    <b>10</b> 
    <b>11</b> 
    <x> 
     <a>12</a> 
     <a>13</a> 
    </x> 
    <b>14</b> 
</root> 

謝謝您的幫助。我試圖自己解決,但我沒有成功。

+0

好問題,+1。查看我的答案,獲得可用於各種XML文檔的更一般和更靈活的解決方案。 –

+0

還添加了XSLT 2.0解決方案。 –

回答

2

這是一個可以產生想要的結果不會對XML文檔施加任何限制,更通用的解決方案 - 我們不認爲任何預先定義的嵌套的水平,或一個元件稱爲b存在:

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

    <xsl:key name="kFollowing" 
    match="a[preceding-sibling::*[1] 
           [self::a] 
      ]" 
    use="concat(
     generate-id(
       preceding-sibling::*[not(self::a)][1] 
        ), 
     generate-id(..) 
       ) 
     "/> 

<xsl:template match="node()|@*"> 
    <xsl:copy> 
    <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="*[a]"> 
    <xsl:apply-templates/> 
</xsl:template> 

<xsl:template match= 
    "a[not(preceding-sibling::*[1][self::a])]"> 

    <xsl:variable name="vGroup" select= 
    ".|key('kFollowing', 
      concat(generate-id(preceding-sibling::*[1]), 
        generate-id(..) 
        ) 
     )"/> 

    <xsl:element name="{name(..)}"> 
    <xsl:apply-templates mode="group" 
    select="$vGroup"/> 
    </xsl:element> 

    <xsl:apply-templates select="$vGroup/*"/> 
</xsl:template> 

<xsl:template match="a" mode="group"> 
    <a> 
    <xsl:apply-templates select="node()[not(self::*)]"/> 
    </a> 
</xsl:template> 

<xsl:template match= 
    "a[preceding-sibling::*[1] 
         [self::a] 
    ]"/> 
</xsl:stylesheet> 

當施加所提供的XML文檔

<root> 
    <p> 
     <a>1</a> 
     <a>2</a> 
     <a> 
      <DEEPSPACENODE/> 
     </a> 
     <b>3</b> 
     <b>4</b> 
     <a>5</a> 
     <a>6</a> 
     <b>7</b> 
    </p> 
    <x> 
     <a>8</a> 
     <a>9</a> 
     <b>10</b> 
     <b>11</b> 
     <a>12</a> 
     <a>13</a> 
     <b>14</b> 
    </x> 
</root> 

想要的,正確的結果產生

<root> 
    <p> 
     <a>1</a> 
     <a>2</a> 
     <a/> 
    </p> 
    <DEEPSPACENODE/> 
    <b>3</b> 
    <b>4</b> 
    <p> 
     <a>5</a> 
     <a>6</a> 
    </p> 
    <b>7</b> 
    <x> 
     <a>8</a> 
     <a>9</a> 
    </x> 
    <b>10</b> 
    <b>11</b> 
    <x> 
     <a>12</a> 
     <a>13</a> 
    </x> 
    <b>14</b> 
</root> 

現在,下面的XML文檔這個解決方案仍然會產生想要的結果,而解決方案by @empo chokes on it

<root> 
    <c> 
    <p> 
     <a>1</a> 
     <a>2</a> 
     <a> 
      <DEEPSPACENODE/> 
     </a> 
     <z>3</z> 
     <z>4</z> 
     <a>5</a> 
     <a>6</a> 
     <b>7</b> 
    </p> 
    <x> 
     <a>8</a> 
     <a>9</a> 
     <b>10</b> 
     <z>11</z> 
     <a>12</a> 
     <a>13</a> 
     <b>14</b> 
    </x> 
    </c> 
</root> 

相同的變換,當在XML文檔上面應用,再次產生正確的,希望引起

<root> 
    <c> 
     <p> 
     <a>1</a> 
     <a>2</a> 
     <a/> 
     </p> 
     <DEEPSPACENODE/> 
     <z>3</z> 
     <z>4</z> 
     <p> 
     <a>5</a> 
     <a>6</a> 
     </p> 
     <b>7</b> 
     <x> 
     <a>8</a> 
     <a>9</a> 
     </x> 
     <b>10</b> 
     <z>11</z> 
     <x> 
     <a>12</a> 
     <a>13</a> 
     </x> 
     <b>14</b> 
    </c> 
</root> 

II。 XSLT 2.0解決方案

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

<xsl:template match="node()|@*" mode="#all"> 
     <xsl:copy> 
     <xsl:apply-templates select="node()|@*"/> 
     </xsl:copy> 
    </xsl:template> 

<xsl:template match="*[a]"> 
    <xsl:for-each-group select="node()" 
         group-adjacent="name() eq 'a'"> 
    <xsl:apply-templates select="current-group()" 
         mode="group"> 
     <xsl:with-param name="pGroup" 
         select="current-group()"/> 
    </xsl:apply-templates> 
    <xsl:apply-templates select="current-group()[self::a]/*"/> 
    </xsl:for-each-group> 
    </xsl:template> 

<xsl:template match="a" mode="group"/> 

<xsl:template mode="group" 
      match="a[not(preceding-sibling::*[1][self::a])]" > 
    <xsl:param name="pGroup" as="node()*"/> 

    <xsl:element name="{name(..)}"> 
    <xsl:apply-templates select="$pGroup" mode="shallow"/> 
    </xsl:element> 
</xsl:template> 

    <xsl:template match="a" mode="shallow"> 
    <a> 
     <xsl:apply-templates select="node()[not(self::*)]"/> 
    </a> 
    </xsl:template> 
</xsl:stylesheet> 
+0

不錯的作品! +1 –

+0

+1。再次感謝@Dimitre! :-))greatgreatgreat – therealmarv

+0

@therealmarv:不客氣。 –

2

檢查這個樣式表:

  • 集團一個元素通過檢查前面的兄弟姐妹
  • 使用相鄰遞歸模板的集合組一個

注意我故意沒管理DEEPSPACENODE,因爲不清楚你想如何處理它:P。您可以使用此轉換作爲起點。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output indent="yes"/> 
    <xsl:strip-space elements="*"/> 
    <xsl:template match="text()"/> 

    <xsl:template match="/*"> 
     <xsl:copy> 
      <xsl:apply-templates select="*/*"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="a[preceding-sibling::*[1][self::b] 
     or not(preceding-sibling::*)]"> 
     <xsl:element name="{name(..)}"> 
      <xsl:apply-templates select="." mode="adjacent"/> 
     </xsl:element> 
    </xsl:template> 

    <xsl:template match="b"> 
     <xsl:copy-of select="."/> 
    </xsl:template> 

    <xsl:template match="a" mode="adjacent"> 
     <a> 
      <xsl:value-of select="self::node()[not(DEEPSPACENODE)]"/> 
     </a> 
     <xsl:apply-templates select=" 
      following-sibling::*[1][self::a]" mode="adjacent"/> 
    </xsl:template> 

</xsl:stylesheet> 

與輸出:

<root> 
    <p> 
     <a>1</a> 
     <a>2</a> 
     <a/> 
    </p> 
    <b>3</b> 
    <b>4</b> 
    <p> 
     <a>5</a> 
     <a>6</a> 
    </p> 
    <b>7</b> 
    <x> 
     <a>8</a> 
     <a>9</a> 
    </x> 
    <b>10</b> 
    <b>11</b> 
    <x> 
     <a>12</a> 
     <a>13</a> 
    </x> 
    <b>14</b> 
</root> 
+1

感謝您的「出發點」! 'DEEPSPACENODE'與'b'相同。唯一的區別是:它是'p'孩子的孩子。它應該重新安排到與'x'或'p'相同的級別。也許我可以自己管理這個。非常感謝。 – therealmarv

+0

好的,那很清楚,但是如果它是不是鄰居中最後一個** **節點的子節點呢? –

+0

最好是我給你的例子:輸入:'

'結果:'

' – therealmarv

相關問題