基于空格分隔的标签列表对项目列表进行分组

时间:2014-12-12 02:50:47

标签: xslt xslt-1.0 xslt-grouping exslt

问题有多方面:

  1. 如何根据标签的特定空格分隔内容进行分类
  2. 如何对缺乏此类特定内容进行分类。
  3. 例如,请采用以下数据:

    <messages>
      <m> 
        <subject>message tagged with A B C</subject>
        <tags>A B C</tags>
      </m>
    
      <m> 
        <subject>message tagged with B C D</subject>
        <tags>B C D</tags>
      </m>
    
      <m> 
        <subject>message tagged with X Y A</subject>
        <tags>X Y A</tags>
      </m>
    
      <m> 
        <subject>message tagged with C X</subject>
        <tags>C X</tags>
      </m>
    
      <m>
        <subject>message tagged with Y</subject>
        <tags>Y</tags>
      </m>
    
    </messages>
    

    给定一组已知标签,比如说

    <xsl:param name="pKnownTags">
      <t>A</t>
      <t>B</t>
    </xsl:param>
    

    我想生成一个看起来像的输出:

    Messages tagged with A:
    * message tagged with A B C
    * message tagged with X Y A
    
    Messages tagged with B:
    * message tagged with A B C
    * message tagged with B C D
    
    Messages tagged with neither:
    * message tagged with C X
    * message tagged with Y 
    

    使用EXSLT很好,但是否则需要1.0解决方案。这可能吗?

2 个答案:

答案 0 :(得分:0)

这不需要任何太花哨的东西。请试试以下内容:

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

  <xsl:param name="pKnownTags">
    <t>A</t>
    <t>B</t>
  </xsl:param>
  <xsl:variable name="pKnownTagsNodeSet" select="exsl:node-set($pKnownTags)/t" />

  <xsl:template match="/messages">
    <xsl:apply-templates select="$pKnownTagsNodeSet">
      <xsl:with-param name="docEl" select="." />
    </xsl:apply-templates>

    <xsl:text>Messages tagged with none of the above:&#xA;</xsl:text>
    <xsl:apply-templates select="m" mode="checkAbsence" />
  </xsl:template>

  <xsl:template match="t">
    <xsl:param name="docEl" select="/.." />

    <xsl:value-of select="concat('Messages tagged with ', ., ':&#xA;')"/>
    <xsl:apply-templates select="$docEl/m[contains(concat(' ', tags, ' '),
                                                   concat(' ', current(), ' '))]" />
    <xsl:text>&#xA;</xsl:text>
  </xsl:template>

  <xsl:template match="m" mode="checkAbsence">
    <xsl:variable name="currentTagsPadded" select="concat(' ', tags, ' ')" />
    <xsl:apply-templates
          select="(.)[not($pKnownTagsNodeSet[contains($currentTagsPadded,
                                                      concat(' ', ., ' '))]
                         )
                     ]" />
  </xsl:template>

  <xsl:template match="m">
    <xsl:value-of select="concat('* ', subject, '&#xA;')"/>
  </xsl:template>

</xsl:stylesheet>

在样本输入上运行时,会产生:

Messages tagged with A:
* message tagged with A B C
* message tagged with X Y A

Messages tagged with B:
* message tagged with A B C
* message tagged with B C D

Messages tagged with none of the above:
* message tagged with C X
* message tagged with Y

答案 1 :(得分:0)

  

使用EXSLT很好

好吧,如果您的处理器支持EXSLT str:tokenize()函数,那么这可能非常简单:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
xmlns:str="http://exslt.org/strings"
extension-element-prefixes="exsl str">
<xsl:output method="text" encoding="UTF-8"/>

<xsl:param name="pKnownTags">
    <t>A</t>
    <t>B</t>
</xsl:param>

<xsl:variable name="tags-set" select="exsl:node-set($pKnownTags)/t" />
<xsl:variable name="xml" select="/" />

<xsl:key name="message-by-tags" match="m" use="str:tokenize(tags)" />

<xsl:template match="/">
    <!-- matching messages -->
    <xsl:for-each select="$tags-set">
        <xsl:variable name="tag" select="." />
        <xsl:value-of select="concat('Messages tagged with ', $tag, ':&#10;')"/>
        <!-- switch context to source document in order to use key -->
        <xsl:for-each select="$xml">
            <xsl:for-each select="key('message-by-tags', $tag)">
                <xsl:value-of select="concat('* ', subject, ':&#10;')"/>
            </xsl:for-each>
        </xsl:for-each>
        <xsl:text>&#10;</xsl:text>
    </xsl:for-each>

    <!-- non-matching messages -->
    <xsl:text>Messages tagged with none:&#10;</xsl:text>
    <xsl:for-each select="messages/m[not(str:tokenize(tags)=$tags-set)]">
        <xsl:value-of select="concat('* ', subject)"/>
        <xsl:if test="position()!=last()">
            <xsl:text>&#10;</xsl:text>
        </xsl:if>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>