2010-01-27 20 views
3

我想使用XSLT選擇摘要以及HTML格式元素。這裏是一個XML的例子:使用XSLT選擇包含HTML標記的n個單詞的摘要

<PUBLDES>The <IT>European Journal of Cancer (including EJC Supplements),</IT> 
is an international comprehensive oncology journal that publishes original 
research, editorial comments, review articles and news on experimental oncology, 
clinical oncology (medical, paediatric, radiation, surgical), translational 
oncology, and on cancer epidemiology and prevention. The Journal now has online 
submission for authors. Please submit manuscripts at 
<SURL>http://ees.elsevier.com/ejc</SURL> and follow the instructions on the 
site.<P/> 

The <IT>European Journal of Cancer (including EJC Supplements)</IT> is the 
official Journal of the European Organisation for Research and Treatment 
of Cancer (EORTC), the European CanCer Organisation (ECCO), the European 
Association for Cancer Research (EACR), the the European Society of Breast 
Cancer Specialists (EUSOMA) and the European School of Oncology (ESO). <P/> 
Supplements to the <IT>European Journal of Cancer</IT> are published under 
the title <IT>EJC Supplements</IT> (ISSN 1359-6349). All subscribers to 
<IT>European Journal of Cancer</IT> automatically receive this publication.<P/> 
To access the latest tables of contents, abstracts and full-text articles 
from <IT>EJC</IT>, including Articles-in-Press, please visit <URL> 
<HREF>http://www.sciencedirect.com/science/journal/09598049</HREF> 
<HTXT>ScienceDirect</HTXT> 
</URL>.</PUBLDES> 

如何從中獲得45個單詞以及其中的HTML標籤。當我使用substring()concat()它刪除標籤(如<IT>等)。

+0

哪一種語言ru使用? – zapping 2010-01-27 08:04:02

+0

@zapping:標題說XSLT已經! – kennytm 2010-01-27 08:17:30

+0

你能使用XSLT2.0還是隻使用XSLT1.0? – 2010-01-27 08:50:04

回答

4

您可能會更好地以編程方式執行此操作,而不是使用純XSLT,但如果您必須使用XSLT,則可以使用這種方法。它涉及多個樣式表,但如果您能夠使用擴展功能,則可以使用節點集並將它們組合成一個大的(並且令人討厭的)樣式表。

第一個樣式表將複製初始XML,但會'發現'它找到的任何文本,以便文本中的每個單詞成爲單獨的'WORD'元素。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <!-- Copy existing nodes and attributes --> 
    <xsl:template match="@*|node()"> 
     <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 
    <!-- Match text nodes --> 
    <xsl:template match="text()"> 
     <xsl:call-template name="tokenize"> 
     <xsl:with-param name="string" select="."/> 
     </xsl:call-template> 
    </xsl:template> 
    <!-- Splits a string into separate elements for each word --> 
    <xsl:template name="tokenize"> 
     <xsl:param name="string"/> 
     <xsl:param name="delimiter" select="' '"/> 
     <xsl:choose> 
     <xsl:when test="$delimiter and contains($string, $delimiter)"> 
      <xsl:variable name="word" select="normalize-space(substring-before($string, $delimiter))"/> 
      <xsl:if test="string-length($word) &gt; 0"> 
       <WORD> 
        <xsl:value-of select="$word"/> 
       </WORD> 
      </xsl:if> 
      <xsl:call-template name="tokenize"> 
       <xsl:with-param name="string" select="substring-after($string, $delimiter)"/> 
       <xsl:with-param name="delimiter" select="$delimiter"/> 
      </xsl:call-template> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:variable name="word" select="normalize-space($string)"/> 
      <xsl:if test="string-length($word) &gt; 0"> 
       <WORD> 
        <xsl:value-of select="$word"/> 
       </WORD> 
      </xsl:if> 
     </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet> 

用來「記號化」的文本字符串的XSLT模板,我從這個問題了這裏:

tokenizing-and-sorting-with-xslt-1-0

(注意,在XSLT2.0,我相信這是一個記號化功能,這將簡化上述)

這將使你的XML是這樣的...

<PUBLDES> 
    <WORD>The</WORD> 
    <IT> 
     <WORD>European</WORD> 
     <WORD>Journal</WORD> 
     <WORD>of</WORD> 
     .... 

依此類推...

接下來,使用另一個XSLT文檔遍歷此XML文檔,僅輸出至前45個單詞元素。要做到這一點,我重複應用一個模板,保持當前發現的總詞數。當匹配節點時,有三種可能性:

  • 匹配WORD元素:輸出它。如果未達到總數,則從下一個兄弟進行處理。
  • 匹配一個元件,其中它下面的字的數量是小於總:複製整個元件,然後從下一個同級上處理攜帶如果總不其中以下詞語的數量達到
  • 匹配元素將超過總數:複製當前節點(但不是其子節點)並繼續在第一個子節點處理。

這裏是樣式表,在其所有的駭人聽聞

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

    <!-- Match root element --> 
    <xsl:template match="/"> 
     <xsl:apply-templates select="descendant::*[1]" mode="word"> 
     <xsl:with-param name="previousWords">0</xsl:with-param> 
     </xsl:apply-templates> 
    </xsl:template> 

    <!-- Match any node --> 
    <xsl:template match="node()" mode="word"> 
     <xsl:param name="previousWords"/> 

     <!-- Number of words below the element (at any depth) --> 
     <xsl:variable name="childWords" select="count(descendant::WORD)"/> 
     <xsl:choose> 
     <!-- Matching a WORD element --> 
     <xsl:when test="local-name(.) = 'WORD'"> 
      <!-- Copy the word --> 
      <WORD> 
       <xsl:value-of select="."/> 
      </WORD> 
      <!-- If there are still words to output, continue processing at next sibling --> 
      <xsl:if test="$previousWords + 1 &lt; $WORDCOUNT"> 
       <xsl:apply-templates select="following-sibling::*[1]" mode="word"> 
        <xsl:with-param name="previousWords"> 
        <xsl:value-of select="$previousWords + 1"/> 
        </xsl:with-param> 
       </xsl:apply-templates> 
      </xsl:if> 
     </xsl:when> 

     <!-- Match a node where the number of words below it is within allowed limit --> 
     <xsl:when test="$childWords &lt;= $WORDCOUNT - $previousWords"> 
      <!-- Copy the element --> 
      <xsl:copy> 
       <!-- Copy all its desecendants --> 
       <xsl:copy-of select="*|@*"/> 
      </xsl:copy> 
      <!-- If there are still words to output, continue processing at next sibling --> 
      <xsl:if test="$previousWords + $childWords &lt; $WORDCOUNT"> 
       <xsl:apply-templates select="following-sibling::*[1]" mode="word"> 
        <xsl:with-param name="previousWords"> 
        <xsl:value-of select="$previousWords + $childWords"/> 
        </xsl:with-param> 
      </xsl:apply-templates> 
     </xsl:if> 
     </xsl:when> 

     <!-- Match nodes where the number of words below it would exceed current limit --> 
     <xsl:otherwise> 
      <!-- Copy the node --> 
      <xsl:copy> 
       <!-- Continue processing at very first child node --> 
       <xsl:apply-templates select="descendant::*[1]" mode="word"> 
        <xsl:with-param name="previousWords"> 
        <xsl:value-of select="$previousWords"/> 
        </xsl:with-param> 
       </xsl:apply-templates> 
      </xsl:copy> 
     </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet> 

如果你輸出只是第4個字,說,這會給你下面的輸出

<PUBLDES> 
    <WORD>The</WORD> 
    <IT> 
     <WORD>European</WORD> 
     <WORD>Journal</WORD> 
     <WORD>of</WORD> 
    </IT> 
</PUBLDES> 

中當然,您還需要另一個轉換來刪除WORD元素,並將文本保留。這應該是相當直接的... ...

雖然這是非常討厭,但它是我現在能想出的最好的!