2012-05-14 50 views
1

我有以下XML:裝飾混合內容的字符的最大數量與XSLT

<p>Lorem ipsum dolor sit amet, <b>consectetur adipisicing</b> elit, <i>sed do<sup>2</sup></i> eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>

我想前200個字符只顯示,但它可能不會在一箇中間切斷字,我想保留格式化元素。因此,上述片段,改造後變爲:

<p>Lorem ipsum dolor sit amet, <b>consectetur adipisicing</b> elit, <i>sed do<sup>2</sup></i> eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ...</p>

有誰知道這是否可能? 在此先感謝!

+0

這不是一個XSLT問題。最好的方法是在JavaScript/jQuey中處理這個問題,在後代節點中累積文本的長度,直到找到一個達到您的限制然後殺死其餘部分。 – 2012-05-15 03:38:33

+0

@torazaburo:實際上,這可以通過XSLT 2.0轉換來實現,解決方案並不困難。 –

+0

Iddo:其實這個單詞,其結尾字符是第200個字符是「ut」。 :) –

回答

2

此XSLT 2.0轉化

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

<xsl:param name="pmaxChars" as="xs:integer" select="200"/> 

<xsl:variable name="vPass1"> 
    <xsl:apply-templates select="/*"/> 
</xsl:variable> 

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

<xsl:template match="/"> 
    <xsl:apply-templates select="$vPass1" mode="pass2"/> 
</xsl:template> 

<xsl:template match= 
"text()[sum(preceding::text()/string-length()) ge $pmaxChars]"/> 

<xsl:template match="text()[not(following::text())]" mode="pass2"> 
    <xsl:variable name="vPrecedingLength" 
    select="sum(preceding::text()/string-length())"/> 

    <xsl:variable name="vRemaininingLength" 
    select="$pmaxChars -$vPrecedingLength"/> 

    <xsl:sequence select= 
    "replace(., 
      concat('(^.{0,', $vRemaininingLength, '})\W.*'), 
      '$1' 
      ) 
    "/> 
</xsl:template> 
</xsl:stylesheet> 

當所提供的XML文檔應用:

<p>Lorem ipsum dolor sit amet, <b>consectetur adipisicing</b> elit, <i>sed do<sup>2</sup></i> eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p> 

產生想要的,正確的結果(一個XML文檔,其中所有文本節點的總長度不超過200,截斷在字邊界上執行,這是truncatio n,其中最大可能的總剩餘串長度):

<p>Lorem ipsum dolor sit amet, <b>consectetur adipisicing</b> elit, <i>sed do<sup>2</sup></i> eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut</p> 

說明

  1. 這是接受的文本字符的最大數目爲全局/外部參數$pmaxChars一個通用的解決方案。

  2. 這是一個雙通解決方案。在pass1中,identity rule被模板覆蓋,該模板刪除所有起始字符都具有索引(在所有文本節點的總體連接中)的大於最大允許字符數的文本節點。因此,pass1的結果是一個XML文檔,其中最大允許長度的「break」出現在最後一個文本節點中。

  3. 在第2遍中,我們使用與最後一個文本節點匹配的模板覆蓋身份規則。我們使用replace()功能:

....

replace(., 
      concat('(^.{0,', $vRemaininingLength, '})\W.*'), 
      '$1' 
      ) 

這將導致整個字符串進行匹配,並在括號中的子表達式來代替。這個子表達式是動態構造的,並匹配從字符串開頭開始幷包含從0到$vRemaininingLength(允許的最大長度減去前面所有文本節點的總長度)字符的最長子字符串,緊接着是字邊界字符。

UPDATE

爲了擺脫導致元素,由於修整沒有文本節點後代(是「空」),只需添加其它的模板:

<xsl:template match= 
"*[(.//text())[1][sum(preceding::text()/string-length()) ge $pmaxChars]]"/> 
+0

謝謝迪米特雷!非常聰明的解決方案! 我已添加以下模板匹配以避免空樣式標記: '' – iddo

+0

@Iddo:不客氣。至於空的元素,在你的問題中,你沒有指定他們被刪除,所以我認爲離開它們是可以的。 –

+0

@Iddo:查看此答案的更新(最後)。 –