我需要一个转换以下XML的XSLT1.0。
<Record>
<Row>
<Name>AAA</Name>
<Surname>Surname1</Surname>
</Row>
<Row>
<Name>BBB</Name>
<Surname>Surname2</Surname>
</Row>
<Row>
<Name>CCC</Name>
<Surname>Surname1</Surname>
</Row>
<Row>
<Name>DDD</Name>
<Surname>Surname2</Surname>
</Row>
<Row>
<Name>EEE</Name>
<Surname>Surname1</Surname>
</Row>
<Row>
<Name>FFF</Name>
<Surname>Surname2</Surname>
</Row>
<Row>
<Name>GGG</Name>
<Surname>Surname1</Surname>
</Row>
<Row>
<Name>HHH</Name>
<Surname>Surname2</Surname>
</Row>
</Record>
我期望的输出是:
<Output>
<Recordset1>
<Record>
<Name>AAA</Name>
<Surname>Surname1</Surname>
</Record>
<Record>
<Name>CCC</Name>
<Surname>Surname1</Surname>
</Record>
</Recordset1>
<Recordset1>
<Record>
<Name>EEE</Name>
<Surname>Surname1</Surname>
</Record>
<Record>
<Name>GGG</Name>
<Surname>Surname1</Surname>
</Record>
</Recordset1>
<Recordset2>
<Record>
<Name>BBB</Name>
<Surname>Surname2</Surname>
</Record>
<Record>
<Name>DDD</Name>
<Surname>Surname2</Surname>
</Record>
</Recordset2>
<Recordset2>
<Record>
<Name>FFF</Name>
<Surname>Surname2</Surname>
</Record>
<Record>
<Name>HHH</Name>
<Surname>Surname2</Surname>
</Record>
</Recordset2>
</Output>
条件是:
记录集1应包含姓氏1节点
记录集2应包含姓氏2节点
输出应按姓氏排序
每个记录集最多有2条记录。
有几个技巧:
- 选择不同的姓氏
- 将姓氏记录分组
- 将姓氏记录分成2组
- 基于不同的姓氏索引创建动态元素名称
这个样式表解决了这些问题:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/Record">
<Output>
<xsl:apply-templates select="//Row[not(./Surname=preceding::Surname)]/Surname" mode="group">
<xsl:sort select="Surname" />
</xsl:apply-templates>
</Output>
</xsl:template>
<xsl:template match="Surname" mode="group">
<xsl:variable name="surname" select="./text()" />
<xsl:variable name="surnameIndex" select="position()" />
<xsl:variable name="surnameGroup" select="/Record/Row[Surname/text()=$surname]" />
<xsl:for-each select="$surnameGroup">
<xsl:variable name="index" select="position()" />
<!-- only create a new record set on the first (or only) member of the output pair -->
<xsl:if test="$index mod 2=1"> <!-- positions are 1 based, not 0 based -->
<xsl:element name="Recordset{$surnameIndex}">
<!-- alternatively, use xsl:copy-of -->
<xsl:apply-templates select="$surnameGroup[$index]" mode="record" />
<xsl:apply-templates select="$surnameGroup[$index+1]" mode="record" />
</xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template match="Row" mode="record">
<Record>
<Name><xsl:value-of select="Name" /></Name>
<Surname><xsl:value-of select="Surname" /></Surname>
</Record>
</xsl:template>
</xsl:stylesheet>
将此样式表应用于输入文档的输出是:
<?xml version="1.0" encoding="UTF-8" ?>
<Output>
<Recordset1>
<Record>
<Name>AAA</Name>
<Surname>Surname1</Surname>
</Record>
<Record>
<Name>CCC</Name>
<Surname>Surname1</Surname>
</Record>
</Recordset1>
<Recordset1>
<Record>
<Name>EEE</Name>
<Surname>Surname1</Surname>
</Record>
<Record>
<Name>GGG</Name>
<Surname>Surname1</Surname>
</Record>
</Recordset1>
<Recordset2>
<Record>
<Name>BBB</Name>
<Surname>Surname2</Surname>
</Record>
<Record>
<Name>DDD</Name>
<Surname>Surname2</Surname>
</Record>
</Recordset2>
<Recordset2>
<Record>
<Name>FFF</Name>
<Surname>Surname2</Surname>
</Record>
<Record>
<Name>HHH</Name>
<Surname>Surname2</Surname>
</Record>
</Recordset2>
</Output>
这可能会对您有所帮助。
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxml="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="msxml">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:key match="Row" name="rows" use="Surname"/>
<xsl:template match="Record">
<Output>
<xsl:for-each select="Row[generate-id(.) = generate-id(key('rows', Surname)[1])]">
<xsl:sort select="Surname" data-type="text" order="ascending"/>
<xsl:variable name="Recordset" select="concat('Recordset',position())"/>
<xsl:variable name="Rows">
<xsl:copy-of select="key('rows', Surname)"/>
</xsl:variable>
<xsl:variable name="RowList" select="msxml:node-set($Rows)"/>
<xsl:for-each select="$RowList/Row[position() mod 2 = 1]">
<xsl:element name="{$Recordset}">
<Record>
<xsl:copy-of select="./*"/>
</Record>
<xsl:if test="following-sibling::Row[1]/*">
<Record>
<xsl:copy-of select="following-sibling::Row[1]/*"/>
</Record>
</xsl:if>
</xsl:element>
</xsl:for-each>
</xsl:for-each>
</Output>
</xsl:template>
</xsl:stylesheet>