2010-03-08 98 views
1

在使用XSLT實現此需求時需要一些幫助,我已經使用SAX解析器實現了此代碼的Java代碼,但由於客戶請求改變了某些內容。XSLT:分割無繼續元素/分組繼續元素

所以我們現在正在使用XSLT進行編譯,並且不需要編譯並部署到Web服務器。我有如下的XML。

實施例1:

<ShotRows> 
    <ShotRow row="3" col="3" bit="1" position="1"/> 
    <ShotRow row="3" col="4" bit="1" position="2"/> 
    <ShotRow row="3" col="5" bit="1" position="3"/> 
    <ShotRow row="3" col="6" bit="1" position="4"/> 
    <ShotRow row="3" col="7" bit="1" position="5"/> 
    <ShotRow row="3" col="8" bit="1" position="6"/> 
    <ShotRow row="3" col="9" bit="1" position="7"/> 
    <ShotRow row="3" col="10" bit="1" position="8"/> 
    <ShotRow row="3" col="11" bit="1" position="9"/> 
</ShotRows> 

輸出1:

<ShotRows> 
    <ShotRow row="3" colStart="3" colEnd="11" /> 
</ShotRows> 
<!-- because the col is continuous from 3 to 11 --> 

實施例2:

<ShotRows> 
    <ShotRow row="3" col="3" bit="1" position="1"/> 
    <ShotRow row="3" col="4" bit="1" position="2"/> 
    <ShotRow row="3" col="6" bit="1" position="3"/> 
    <ShotRow row="3" col="7" bit="1" position="4"/> 
    <ShotRow row="3" col="8" bit="1" position="5"/> 
    <ShotRow row="3" col="10" bit="1" position="6"/> 
    <ShotRow row="3" col="11" bit="1" position="7"/> 
    <ShotRow row="3" col="15" bit="1" position="8"/> 
    <ShotRow row="3" col="19" bit="1" position="9"/> 
</ShotRows> 

輸出2:

<ShotRows> 
    <ShotRow row="3" colStart="3" colEnd="4" /> 
    <ShotRow row="3" colStart="6" colEnd="8" /> 
    <ShotRow row="3" colStart="10" colEnd="11" /> 
    <ShotRow row="3" colStart="15" colEnd="15" /> 
    <ShotRow row="3" colStart="19" colEnd="19" /> 
</ShotRows> 

其基本思想是將任何連續的列組合到一個元素中,例如col 3到4,col 6到8,col 10到11,col 15只有一個,col 19只有一個。提前致謝。

回答

2

使用Java,你可以使用Saxon 9和XSLT 2.0如下:

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="2.0"> 

    <xsl:output indent="yes"/> 

    <xsl:template match="ShotRows"> 
    <xsl:copy> 
     <xsl:for-each-group select="ShotRow" group-adjacent="number(@col) - position()"> 
     <ShotRow row="{@row}" colStart="{@col}" colEnd="{@col + count(current-group()) - 1}"/> 
     </xsl:for-each-group> 
    </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 
+0

簡單而優雅,+1。:) – Tomalak 2010-03-08 12:34:52

+0

XSLT 2.0也可以通過Saxon.NET在.NET中使用。 – 2010-03-08 13:40:49

+0

我們在java中使用Saxon 9.1 – Gerald 2010-03-08 14:51:43

0

這感覺有點混亂,因爲迭代處理通常在XSLT中執行。

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

    <xsl:output method="xml" indent="yes" /> 

    <xsl:template match="ShotRows"> 
     <xsl:copy> 
      <xsl:apply-templates select="ShotRow[1]" /> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="ShotRow"> 
     <xsl:call-template name="ShotRow"> 
      <xsl:with-param name="start" select="@col" /> 
      <xsl:with-param name="shotrow" select="." /> 
     </xsl:call-template> 
    </xsl:template> 

    <xsl:template name="ShotRow"> 
     <xsl:param name="start" /> 
     <xsl:param name="shotrow" /> 

     <xsl:choose> 
      <xsl:when test="$shotrow/@row = $shotrow/following-sibling::ShotRow[1]/@row and 1 + number($shotrow/@col) = number($shotrow/following-sibling::ShotRow[1]/@col)"> 
       <xsl:call-template name="ShotRow"> 
        <xsl:with-param name="start" select="$start" /> 
        <xsl:with-param name="shotrow" select="$shotrow/following-sibling::ShotRow[1]" /> 
       </xsl:call-template> 

      </xsl:when> 
      <xsl:otherwise> 
       <ShotRow row="{$shotrow/@row}" colStart="{$start}" colEnd="{$shotrow/@col}" /> 
       <xsl:apply-templates select="$shotrow/following-sibling::ShotRow[1]" /> 

      </xsl:otherwise> 
     </xsl:choose> 

    </xsl:template> 

</xsl:stylesheet> 
+0

@Gerald:有一個在我張貼的替代品。 – Tomalak 2010-03-08 11:53:46

1

通過精心設計的XPath表達式,這是一個簡單的選擇和複製操作。

<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
> 
    <xsl:template match="ShotRows"> 
    <xsl:copy> 
     <xsl:apply-templates select="ShotRow[ 
     not(preceding-sibling::ShotRow) 
     or 
     not(@col = preceding-sibling::ShotRow[1]/@col + 1) 
     ]" /> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="ShotRow"> 
    <xsl:copy> 
     <xsl:copy-of select="@row" /> 
     <xsl:attribute name="colStart"> 
     <xsl:value-of select="@col" /> 
     </xsl:attribute> 
     <xsl:attribute name="colEnd"> 
     <xsl:value-of select="(. | following-sibling::ShotRow)[ 
      not(@col = following-sibling::ShotRow[1]/@col - 1) 
     ][1]/@col" /> 
     </xsl:attribute> 
    </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

產生您要求的完全相同的輸出。第一XPath表達式是:

ShotRow[ 
    not(preceding-sibling::ShotRow) 
    or 
    not(@col = preceding-sibling::ShotRow[1]/@col + 1) 
] 

和它選擇所有<ShotRow>節點即

  • 要麼沒有前身,即在一組
  • 或他們@col第一(或唯一的)一個不完全是一個比他們各自的前任的
  • ERGO更多:這些條件表示一個連續範圍的開始
  • 我已經打上所有位置對他們來說,這是#s低於

第二個表達真實更是一點點微妙:

(. | following-sibling::ShotRow)[ 
    not(@col = following-sibling::ShotRow[1]/@col - 1) 
][1]/@col 
  • (. | following-sibling::ShotRow)是當前節點的並集和所有下面的兄弟姐妹—我會使用「以下同胞或自身」,但不幸的是這樣的軸不存在;)這些節點的
  • ,它選擇其@col的那些不是一個小於各自的繼任者的
  • 麥角:該條件表示連續範圍的(請注意,此選擇提前任何連續範圍的所有端)
  • 這些節點
  • ,需要第一個(這是合乎邏輯的,我們感興趣的是「一個連續範圍的第一端」,或者離我們最近的一個)
  • 我已標記爲他們這一切職務與#e低於

你的榜樣真:

<ShotRows> 
    <ShotRow row="3" col="3" bit="1" position="1"/><!-- #s --> 
    <ShotRow row="3" col="4" bit="1" position="2"/><!-- #e --> 
    <ShotRow row="3" col="6" bit="1" position="3"/><!-- #s --> 
    <ShotRow row="3" col="7" bit="1" position="4"/> 
    <ShotRow row="3" col="8" bit="1" position="5"/><!-- #e --> 
    <ShotRow row="3" col="10" bit="1" position="6"/><!-- #s --> 
    <ShotRow row="3" col="11" bit="1" position="7"/><!-- #e --> 
    <ShotRow row="3" col="15" bit="1" position="8"/><!-- #s #e --> 
    <ShotRow row="3" col="19" bit="1" position="9"/><!-- #s #e --> 
</ShotRows> 

輸出:

<ShotRows> 
    <ShotRow row="3" colStart="3" colEnd="4" /> 
    <ShotRow row="3" colStart="6" colEnd="8" /> 
    <ShotRow row="3" colStart="10" colEnd="11" /> 
    <ShotRow row="3" colStart="15" colEnd="15" /> 
    <ShotRow row="3" colStart="19" colEnd="19" /> 
</ShotRows> 

編輯 - 上述修改版本使用XSL密鑰。對於大型輸入文檔,性能增益應該變得明顯,主要是因爲'kEnd'減少了處理時間。 'kStart'沒有太大的影響,我只將它包含在代碼對稱中。

<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
> 
    <xsl:key 
    name="kStart" 
    match="ShotRow[ 
     not(preceding-sibling::ShotRow) 
     or 
     not(@col = preceding-sibling::ShotRow[1]/@col + 1) 
    ]" 
    use="generate-id(..)" 
    /> 
    <xsl:key 
    name="kEnd" 
    match="ShotRow[ 
     (. | following-sibling::ShotRow)[ 
     not(@col = following-sibling::ShotRow[1]/@col - 1) 
     ] 
    ]" 
    use="concat(generate-id(..), ':', generate-id())" 
    /> 

    <xsl:template match="ShotRows"> 
    <xsl:copy> 
     <xsl:apply-templates select="key('kStart', generate-id(.))" /> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="ShotRow"> 
    <xsl:copy> 
     <xsl:copy-of select="@row" /> 
     <xsl:attribute name="colStart"> 
     <xsl:value-of select="@col" /> 
     </xsl:attribute> 
     <xsl:attribute name="colEnd">   
     <xsl:value-of select="key('kEnd', 
      concat(generate-id(..), ':', generate-id()) 
     )[1]/@col" /> 
     </xsl:attribute> 
    </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

該邏輯與上面解釋的完全相同。

+0

男士感謝您的答案,我們非常感謝。這裏有一個問題,我發佈的XML只是實際XML的一小部分。我們預計約有1000行和1000列。在性能方面我們應該考慮什麼? – Gerald 2010-03-08 12:09:13

+0

@傑拉德:只需測試一下。我的猜測是我的解決方案比@ Lachlan更快,更穩定。此解決方案不使用遞歸,所以你將永遠不會遇到「堆棧溢出」錯誤(無雙關語意)。我可以稍微考慮一下用XSL鍵改進這個解決方案。 – Tomalak 2010-03-08 12:14:04

+0

@Gerald:如果你發佈了一些真實的數字和每個解決方案的性能,我將不勝感激。 – Tomalak 2010-03-08 12:33:35