2011-01-11 49 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>