2011-01-11 87 views
0

重複節點考慮下面的XML:去除XSL輸出

<record> 
    <category>Sport/Racket Sports/Tennis</category> 
    <category>Sport/Racket Sports/Badminton</category> 
</record> 

我想分手,這樣下面的XML產生的類別:

<add> 
    <doc> 
     <field name="category_0">Sport</field> 
     <field name="category_1">Sport/Racket Sports</field> 
     <field name="category_2">Sport/Racket Sports/Tennis</field> 
     <field name="category_2">Sport/Racket Sports/Badminton</field> 
    </doc> 
</add> 

我已經成功地產生的東西幾乎在那裏..我現在需要一種方法來刪除重複?有任何想法嗎?

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:output indent="yes"/> 
    <xsl:template match="record"> 
     <add> 
      <doc> 
       <xsl:for-each select="category[. != '']"> 
        <xsl:call-template name="split-cats"> 
         <xsl:with-param name="prefix" select="''"/> 
         <xsl:with-param name="text" select="."/> 
         <xsl:with-param name="level" select="number(0)"/> 
        </xsl:call-template> 
       </xsl:for-each> 
      </doc> 
     </add> 
    </xsl:template> 

    <xsl:template name="split-cats"> 
     <xsl:param name="text" select="."/> 
     <xsl:param name="prefix"/> 
     <xsl:param name="level" select="0"/> 
      <xsl:choose> 
       <xsl:when test="contains($text, '/')"> 
        <field> 
         <xsl:attribute name="name"> 
          <xsl:text>category_</xsl:text><xsl:value-of select="$level"/> 
         </xsl:attribute> 
         <xsl:value-of select="concat($prefix, substring-before($text, '/'))"/> 
        </field> 
        <xsl:call-template name="split-cats"> 
         <xsl:with-param name="prefix" select="concat($prefix, concat(substring-before($text, '/'), '/'))"/> 
         <xsl:with-param name="text" select="substring-after($text, '/')"/> 
         <xsl:with-param name="level" select="$level + 1"/> 
        </xsl:call-template> 
       </xsl:when> 
       <xsl:otherwise> 
        <field> 
         <xsl:attribute name="name"> 
          <xsl:text>category_</xsl:text><xsl:value-of select="$level"/> 
         </xsl:attribute> 
         <xsl:value-of select="concat($prefix, $text)"/> 
        </field> 
       </xsl:otherwise> 
      </xsl:choose>   
    </xsl:template> 



</xsl:stylesheet> 

這個模板產生:

<add> 
    <doc> 
     <field name="category_0">Sport</field> 
     <field name="category_1">Sport/Racket Sports</field> 
     <field name="category_2">Sport/Racket Sports/Tennis</field> 
     <field name="category_0">Sport</field> 
     <field name="category_1">Sport/Racket Sports</field> 
     <field name="category_2">Sport/Racket Sports/Badminton</field> 
    </doc> 
</add> 

正如你可以看到有SportSport/Racket Sports在那裏兩次:(

FYI:我需要能夠做到這一點使用XSLT 1.0

謝謝

戴夫

+0

請,在一個單獨的問題中解釋什麼是產出的要求/規則(特別是,它不是清算如何形成類別名稱)。我認爲可以生成更簡單的解決方案,並且可以完全避免重複的問題。 – 2011-01-11 14:04:45

+0

啊是的..對不起,數字表示「0」是根級別的類別的「級別」。在這種情況下,「體育」和「1」是子類別的第一級別,2是子類別的第二級別等等。這是用來將文檔發送到Solr的符號。看看這封電子郵件http://search.lucidimagination中的第三個選項。com/search/document/8a14673728e3a722/implements_hierarchical_facet – CraftyFella 2011-01-11 14:10:41

回答

1

這裏是一個直截了當的辦法,簡單地使用你的代碼創建結果Muenchian分組的插入第二個轉換步驟:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" 
    xmlns:exsl="http://exslt.org/common" 
    exclude-result-prefixes="exsl"> 
    <xsl:output indent="yes"/> 

    <xsl:key name="k1" match="cats/field" use="."/> 

    <xsl:template match="record"> 
     <xsl:variable name="cats"> 
      <cats> 
       <xsl:for-each select="category[. != '']"> 
        <xsl:call-template name="split-cats"> 
         <xsl:with-param name="prefix" select="''"/> 
         <xsl:with-param name="text" select="."/> 
         <xsl:with-param name="level" select="0"/> 
        </xsl:call-template> 
       </xsl:for-each> 
      </cats> 
     </xsl:variable> 
     <add> 
      <doc> 
       <xsl:copy-of select="exsl:node-set($cats)/cats/field[generate-id() = generate-id(key('k1', .)[1])]"/> 
      </doc> 
     </add> 
    </xsl:template> 

    <xsl:template name="split-cats"> 
     <xsl:param name="text" select="."/> 
     <xsl:param name="prefix"/> 
     <xsl:param name="level" select="0"/> 
      <xsl:choose> 
       <xsl:when test="contains($text, '/')"> 
        <field> 
         <xsl:attribute name="name"> 
          <xsl:text>category_</xsl:text><xsl:value-of select="$level"/> 
         </xsl:attribute> 
         <xsl:value-of select="concat($prefix, substring-before($text, '/'))"/> 
        </field> 
        <xsl:call-template name="split-cats"> 
         <xsl:with-param name="prefix" select="concat($prefix, concat(substring-before($text, '/'), '/'))"/> 
         <xsl:with-param name="text" select="substring-after($text, '/')"/> 
         <xsl:with-param name="level" select="$level + 1"/> 
        </xsl:call-template> 
       </xsl:when> 
       <xsl:otherwise> 
        <field> 
         <xsl:attribute name="name"> 
          <xsl:text>category_</xsl:text><xsl:value-of select="$level"/> 
         </xsl:attribute> 
         <xsl:value-of select="concat($prefix, $text)"/> 
        </field> 
       </xsl:otherwise> 
      </xsl:choose>   
    </xsl:template> 



</xsl:stylesheet> 

,使得使用的exsl:node-set但是,如果你在瀏覽器針對XSLT 1.0那麼對於IE/MSXML,您需要使用http://dpcarlisle.blogspot.com/2007/05/exslt-node-set-function.html中顯示的腳本修復它。

1

另一種不使用擴展功能來做到這一點的方法(但它不一定像使用Muenchian分組一樣高效)是添加一個檢查來比較以前的分類記錄,看它們是否以你將要使用的字符串開頭約

<xsl:if test="not(/record/category 
       [. != ''] 
       [position() &lt; $pos] 
       [substring(., 1, string-length($field-text)) = $field-text])"> 

在該位的代碼$ POS是包含當前正在匹配當前類元件的位置的參數,並且$場文本是含有你是文本的可變即將輸出。

下面是完整的XSLT樣式表,這也應該給你輸出你的願望

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

    <xsl:template match="record"> 
     <add> 
     <doc> 
      <xsl:for-each select="category[. != '']"> 
       <xsl:call-template name="split-cats"> 
        <xsl:with-param name="prefix" select="''"/> 
        <xsl:with-param name="text" select="."/> 
        <xsl:with-param name="level" select="number(0)"/> 
        <!-- Position of the current category --> 
        <xsl:with-param name="pos" select="position()"/> 
       </xsl:call-template> 
      </xsl:for-each> 
     </doc> 
     </add> 
    </xsl:template> 

    <xsl:template name="split-cats"> 
     <xsl:param name="text" select="."/> 
     <xsl:param name="prefix"/> 
     <xsl:param name="level" select="0"/> 
     <xsl:param name="pos"/> 
     <xsl:choose> 
     <xsl:when test="contains($text, '/')"> 
      <xsl:variable name="field-text" select="concat($prefix, substring-before($text, '/'))"/> 
      <!-- Test no previous category begins with the text we are about to output --> 
      <xsl:if test="not(/record/category 
          [. != ''] 
          [position() &lt; $pos] 
          [substring(., 1, string-length($field-text)) = $field-text])"> 
       <field> 
        <xsl:attribute name="name"> 
        <xsl:text>category_</xsl:text> 
        <xsl:value-of select="$level"/> 
        </xsl:attribute> 
        <xsl:value-of select="$field-text"/> 
       </field> 
      </xsl:if> 
      <xsl:call-template name="split-cats"> 
       <xsl:with-param name="prefix" select="concat($prefix, concat(substring-before($text, '/'), '/'))"/> 
       <xsl:with-param name="text" select="substring-after($text, '/')"/> 
       <xsl:with-param name="level" select="$level + 1"/> 
       <xsl:with-param name="pos" select="$pos"/> 
      </xsl:call-template> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:variable name="field-text" select="concat($prefix, $text)"/> 
      <!-- Test no previous category begins with the text we are about to output --> 
      <xsl:if test="not(/record/category 
          [. != ''] 
          [position() &lt; $pos] 
          [substring(., 1, string-length($field-text)) = $field-text])"> 
       <field> 
        <xsl:attribute name="name"> 
        <xsl:text>category_</xsl:text> 
        <xsl:value-of select="$level"/> 
        </xsl:attribute> 
        <xsl:value-of select="$field-text"/> 
       </field> 
      </xsl:if> 
     </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet> 
1

沒有擴展功能,這個樣式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:strip-space elements="*"/> 
    <xsl:template match="record"> 
     <add> 
      <doc> 
       <xsl:apply-templates select="category[1]"/> 
      </doc> 
     </add> 
    </xsl:template> 
    <xsl:template match="category" name="category"> 
     <xsl:param name="pOutput"/> 
     <xsl:param name="pPrefix"/> 
     <xsl:param name="pLevel" select="0"/> 
     <xsl:param name="pSequence" select="concat(.,'/')"/> 
     <xsl:choose> 
      <xsl:when test="$pSequence"> 
       <xsl:variable name="vItem" 
           select="concat($pPrefix, 
              substring-before($pSequence, 
                   '/'))"/> 
       <xsl:variable name="vOutput" 
           select="concat('|',$vItem,'|')"/> 
       <xsl:if test="not(contains($pOutput,$vOutput))"> 
        <field name="category_{$pLevel}"> 
         <xsl:value-of select="$vItem"/> 
        </field> 
       </xsl:if> 
       <xsl:call-template name="category"> 
        <xsl:with-param name="pOutput" 
            select="concat($pOutput,$vOutput)"/> 
        <xsl:with-param name="pPrefix" 
            select="concat($vItem,'/')"/> 
        <xsl:with-param name="pLevel" select="$pLevel + 1"/> 
        <xsl:with-param name="pSequence" 
            select="substring-after($pSequence,'/')"/> 
       </xsl:call-template> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:apply-templates select="following-sibling::category[1]"> 
        <xsl:with-param name="pOutput" select="$pOutput"/> 
       </xsl:apply-templates> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet> 

輸出:

<add> 
    <doc> 
     <field name="category_0">Sport</field> 
     <field name="category_1">Sport/Racket Sports</field> 
     <field name="category_2">Sport/Racket Sports/Tennis</field> 
     <field name="category_2">Sport/Racket Sports/Badminton</field> 
    </doc> 
</add>