我正在尝试使用 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() > 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>
似乎找不到任何专门满足我需求的东西。谢谢!
在 XSLT1.0 中,要将字符串转换为小写,您需要在 xpath 中使用相当繁琐的翻译函数。
translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')
此外,您的问题是分组问题之一,在 XSLT1.0 中,这通常意味着一种称为 Meunchian 分组的技术。为此,您首先定义一个键来查找所需组中的项目
<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']" />