包含重复行的xslt在for-each中不区分大小写

时间:2012-04-17 21:10:35

标签: xslt xslt-1.0

我正在尝试使用XSLT编写循环,以便它自动将具有相同ID的所有项目分组,但不区分大小写。不幸的是,我试图解析的数据是客户端驱动的,因此我无法在加载之前更改它。 无论这里是XML结构......

<Document>
    <Row>
        <Cell>ID</Cell>
    </Row>
    <Row>
        <Cell>hi</Cell>
    </Row>
    <Row>
        <Cell>Hi</Cell>
    </Row>
    <Row>
        <Cell>Hello</Cell>
    </Row>
    <Row>
        <Cell>Hello</Cell>
    </Row>
    <Row>
        <Cell>Hola</Cell>
    </Row>
</Document>

这是我目前使用的XSLT ......

  <xsl:template match="Document">
    <NewDocument xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <xsl:for-each select="//Row[position() &gt; 1]/Cell[1][not(.=preceding::Row/Cell[1])]">
        <xsl:variable name="currentOrderID" select="." />
        <xsl:variable name="currentOrderGroup" select="//Row[Cell[1] = $currentOrderID]" />

        <MainID>
          <xsl:value-of select="$currentOrderGroup[1]/Cell[1]"/>
        </MainID>
        <IDs>
          <xsl:for-each select="$currentOrderGroup">
            <id>
              <xsl:value-of select="Cell[1]"/>
            </id>
          </xsl:for-each>
        </IDs>
      </xsl:for-each>
    </NewDocument>
  </xsl:template>

这只是按照CaSe SeNSiTiVe方式预期完成的事情...... 我一直试图在那里使用翻译,以使一切都大写,但我似乎无法正确的语法。

我想在这里实现的结果是:

<NewDocument>
  <MainID>hi</MainID>
  <IDs>
    <id>hi</id>
    <id>Hi</id>
  </IDs>  
  <MainID>Hello</MainID>
  <IDs>
    <id>Hello</id>
    <id>Hello</id>
  </IDs>
  <MainID>Hola</MainID>
  <IDs>
    <id>Hola</id>
  </IDs>
</NewDocument>

似乎无法找到我需要的任何东西。 谢谢!

1 个答案:

答案 0 :(得分:2)

在XSLT1.0中,要将字符串转换为小写,您需要在xpath中使用相当繁琐的 translate 函数。

translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')

此外,您的问题是分组问题,而在XSLT1.0中,这通常意味着一种称为Meunchian Grouping的技术。为此,您首先要定义一个键,以便在您需要的组中查找项目

<xsl:key 
   name="Cell" 
   match="Cell" 
   use="translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')"/>

这里我们根据(小写)文本内容查找单元格。

要查找每个组中的第一个元素,您需要在XML中查找 Cell 元素,这些元素恰好是查找键中出现的第一个元素

<xsl:apply-templates 
   select="Row/Cell
   [generate-id() 
    = generate-id(
       key('Cell', 
         translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'))[1])]"/>

然后,当您匹配第一个元素时,您可以通过查看键来匹配组中的所有元素。

这是完整的XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:key name="Cell" match="Cell" use="translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')"/>

   <xsl:template match="Document">
      <NewDocument>
         <xsl:apply-templates select="Row/Cell[generate-id() = generate-id(key('Cell', translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'))[1])]"/>
      </NewDocument>
   </xsl:template>

   <xsl:template match="Cell">
      <MainID>
         <xsl:value-of select="."/>
      </MainID>
      <IDs>
         <xsl:apply-templates select="key('Cell', translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'))" mode="group"/>
      </IDs>
   </xsl:template>

   <xsl:template match="Cell" mode="group">
      <id>
         <xsl:value-of select="."/>
      </id>
   </xsl:template>
</xsl:stylesheet>

请注意使用模式属性来区分与 Cell 元素匹配的两个模板。

应用于XML时,输出以下内容:

<NewDocument>
   <MainID>ID</MainID>
   <IDs>
      <id>ID</id>
   </IDs>
   <MainID>hi</MainID>
   <IDs>
      <id>hi</id>
      <id>Hi</id>
   </IDs>
   <MainID>Hello</MainID>
   <IDs>
      <id>Hello</id>
      <id>Hello</id>
   </IDs>
   <MainID>Hola</MainID>
   <IDs>
      <id>Hola</id>
   </IDs>
</NewDocument>

注意,我不确定如何处理带有 ID 的Cell作为值,所以我把它留在了。如果你想要排除它,只需将此行添加到XSLT

<xsl:template match="Cell[. = 'ID']" />