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>

似乎找不到任何适合我需要的东西。谢谢!

4

1 回答 1

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>

注意mode属性的使用,以区分匹配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作为值的单元格,所以我把它留在里面。如果你确实想排除它,只需将此行添加到 XSLT

<xsl:template match="Cell[. = 'ID']" />
于 2012-04-17T21:55:18.570 回答