将唯一的 XML 元素值添加到 select 列表

Add unique XML Element values to a select list

我正在尝试将唯一的 XML 子元素值添加到 select 列表中。这是我目前所拥有的

XML:

<Student>
  <record>
    <Name>Jack</Name>
  </record>
  <record>
    <Name>Jack</Name>
  </record>
  <record>
    <Name>John</Name>
  </record>
  <record>
    <Name>John</Name>
  </record>
  <record>
    <Name>John</Name>
  </record>
  <record>
    <Name>Jill</Name>
  </record>
  <record>
    <Name>Jill</Name>
  </record>
  <record>
    <Name>James</Name>
  </record>
</Student>

XSLT:

  <xsl:key name="NameKey" match="Name" use="."/>

  <xsl:template match="Student">
    <table>
      <tr>
        <th>Name</th>
        <td>
          <select>
              <xsl:for-each select="record">
                <option>
                <xsl:element name="Name">
                  <xsl:value-of select="Name[generate-id() = generate-id(key('NameKey',.)[1])]" />
                </xsl:element>
                </option>
              </xsl:for-each>            
          </select>
        </td>
       </tr>
      <xsl:apply-templates select="/record" />
    </table>
  </xsl:template>
</xsl:stylesheet>

我已成功获取列表中的唯一值,但列表中的非唯一值也显示为空字符串。所以我的列表具有以下值:

Jack

John


Jill

James

有什么办法可以去掉列表中的那些空字符串值吗?

Is there any way to getting rid of those empty string values in the list?

是的,只需将带有键查找的谓词移动到 xsl:for-each。使用您当前的代码,所有 将这些节点交给 xsl:for-each,包括重复项。

顺便说一句,这一行

<xsl:apply-templates select="/record" />

不做任何事情,因为最外层的元素节点没有被调用record。你来这里的目的是什么?

XSLT 样式表

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

  <xsl:output method="html" encoding="UTF-8" indent="yes" />
  <xsl:key name="NameKey" match="Name" use="."/>

  <xsl:template match="Student">
    <table>
      <tr>
        <th>Name</th>
        <td>
          <select>
              <xsl:for-each select="record/Name[generate-id() = generate-id(key('NameKey',.)[1])]">
                <option>
                <xsl:element name="Name">
                  <xsl:value-of select="." />
                </xsl:element>
                </option>
              </xsl:for-each>            
          </select>
        </td>
       </tr>
      <xsl:apply-templates select="/record" />
    </table>
  </xsl:template>
</xsl:stylesheet>

HTML输出

<table>
   <tr>
      <th>Name</th>
      <td>
         <select>
            <option>
               <Name>Jack</Name>
            </option>
            <option>
               <Name>John</Name>
            </option>
            <option>
               <Name>Jill</Name>
            </option>
            <option>
               <Name>James</Name>
            </option>
         </select>
      </td>
   </tr>
</table>

渲染HTML

我想补充一点,这也可以通过使用 [not(.=preceding::*)] 来实现。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:output method="html" encoding="UTF-8" indent="yes" />

    <xsl:template match="Student">
        <table>
            <tr>
                <th>Name</th>
                <td>
                    <select>
                        <xsl:for-each select="record/Name[not(.=preceding::*)]">
                            <option>
                                <xsl:element name="Name">
                                    <xsl:value-of select="." />
                                </xsl:element>
                            </option>
                        </xsl:for-each>            
                    </select>
                </td>
            </tr>
            <xsl:apply-templates select="/record" />
        </table>
    </xsl:template>
</xsl:stylesheet>

我个人认为这样更清楚,您只处理每个 Name 元素一次。