将唯一的XML元素值添加到选择列表中

时间:2015-01-05 17:59:53

标签: xml asp.net-mvc xslt xslt-1.0

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

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

有没有办法摆脱列表中的那些空字符串值?

2 个答案:

答案 0 :(得分:1)

  

有没有办法摆脱列表中的那些空字符串值?

是的,只需将带有键查找的谓词移动到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

  

enter image description here

答案 1 :(得分:1)

我想补充一点,这也可以通过使用[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元素一次。