【问题标题】:Group by and filter XML data with XSL使用 XSL 对 XML 数据进行分组和过滤
【发布时间】:2010-01-27 11:41:17
【问题描述】:

我有以下 XML 代码:

<root>
    <options>
        <companies>
            <company url="http://www.brown.com">Brown LLC</company>
            <company url="http://www.yellow.com">Yellow LLC</company>
            <company url="http://www.black.com">Black LLC</company>
            <company url="http://www.bourdeaux.com">Bourdeaux LLC</company>
            <company url="http://www.orange.com">Orange LLC</company>           
        </companies>
    </options>
</root>

我需要用它做两件事:

  1. 使用公司节点中的唯一首字母构建一个 html 下拉列表。如:

    <select id="colors">
        <option value="B">B</option>
        <option value="O">O</option>
        <option value="Y">Y</option>
    </select>
    
  2. 建立一个二级下拉列表,列出以特定字母开头的所有公司。如:

    <select id="companiesB">
        <option value="http://www.black.com">Black LLC</option>
        <option value="http://www.bordeaux.com">Bordeaux LLC</option>
        <option value="http://www.brown.com">Brown LLC</option>
    </select>
    

任何帮助将不胜感激!

【问题讨论】:

    标签: xml xslt group-by


    【解决方案1】:

    首先,您需要定义一个键,将共享相同首字母的所有 company 元素“分组”在一起

    <xsl:key name="companyLetter" match="company" use="substring(text(), 1, 1)" />
    

    接下来,您将遍历所有 company 元素

    <xsl:for-each select="options/companies/company">
    

    但是,您只想处理 company 元素,前提是该元素的首字母第一次出现。为此,您可以在密钥中查找第一个字母的第一个元素,并查看它是否相同。元素比较是使用 generate-id() 函数完成的

    <xsl:variable name="firstLetter" select="substring(text(), 1, 1)" />
    <xsl:if test="generate-id(.) = generate-id(key('companyLetter', $firstLetter)[1])" >
    

    把这个放在一起

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
       <xsl:key name="companyLetter" match="company" use="substring(text(), 1, 1)"/>
       <xsl:template match="/root">
          <select id="colors">
             <xsl:for-each select="options/companies/company">
                <xsl:sort select="text()"/>
                <xsl:variable name="firstLetter" select="substring(text(), 1, 1)"/>
                <xsl:if test="generate-id(.) = generate-id(key('companyLetter', $firstLetter)[1])">
                   <option>
                      <xsl:attribute name="value">
                         <xsl:value-of select="$firstLetter"/>
                      </xsl:attribute>
                      <xsl:value-of select="$firstLetter"/>
                   </option>
                </xsl:if>
             </xsl:for-each>
          </select>
       </xsl:template>
    </xsl:stylesheet>
    

    对于第二个下拉菜单,您可以使用将字母作为参数传递的命名模板。您可以使用与上述相同的键查找该字母的所有元素。

    <xsl:template name="Companies">
       <xsl:param name="firstLetter"/>
       <select>
          <xsl:attribute name="id">
             <xsl:value-of select="$firstLetter"/>
          </xsl:attribute>
          <xsl:for-each select="key('companyLetter', $firstLetter)">
             <xsl:sort select="text()"/>
             <option>
                <xsl:attribute name="value">
                   <xsl:value-of select="@url"/>
                </xsl:attribute>
                <xsl:value-of select="text()"/>
             </option>
          </xsl:for-each>
       </select>
    </xsl:template>
    

    调用模板,只是简单的传递所需参数的情况,例如

    <xsl:call-template name="Companies">
       <xsl:with-param name="firstLetter">B</xsl:with-param>
    </xsl:call-template>
    

    当然,如果您想显示所有可能的首字母的所有下拉菜单,您可以将其设为 for-each 循环。

    【讨论】:

      【解决方案2】:

      这里有两个样式表,第一个用于生成第一个选择:

      <xsl:stylesheet
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="1.0">
      
        <xsl:output method="html" indent="yes"/>
        <xsl:strip-space elements="*"/>
      
        <xsl:key name="k1" match="company" use="substring(., 1, 1)"/>
      
        <xsl:template match="companies">
          <select id="colors">
            <xsl:apply-templates select="company[generate-id() = generate-id(key('k1', substring(., 1, 1))[1])]">
              <xsl:sort select="substring(., 1, 1)" data-type="text"/>
            </xsl:apply-templates>
          </select>
        </xsl:template>
      
        <xsl:template match="company">
          <option value="{substring(., 1, 1)}">
            <xsl:value-of select="substring(., 1, 1)"/>
          </option>
        </xsl:template>
      
      </xsl:stylesheet>
      

      第二个用于产生第二个选择元素:

      <xsl:stylesheet
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="1.0">
      
        <xsl:param name="c" select="'B'"/>
      
        <xsl:output method="html" indent="yes"/>
        <xsl:strip-space elements="*"/>
      
        <xsl:template match="companies">
          <select id="companies{$c}">
            <xsl:apply-templates select="company[substring(., 1, 1) = $c]">
              <xsl:sort select="." data-type="text"/>
            </xsl:apply-templates>
          </select>
        </xsl:template>
      
        <xsl:template match="company">
          <option value="{@url}"><xsl:value-of select="."/></option>
        </xsl:template>
      
      </xsl:stylesheet>
      

      【讨论】:

        【解决方案3】:

        您应该查看 Muenchian Method 以在 XSLT 中进行分组。

        【讨论】:

        • 是的,知道...但仍然做不到...因此这里的问题:)
        猜你喜欢
        • 2015-03-20
        • 2010-10-18
        • 1970-01-01
        • 2017-07-12
        • 1970-01-01
        • 2013-01-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多