XSLT1.0对XML进行排序和分组



我需要一个转换以下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应包含姓氏1节点

  2. 记录集2应包含姓氏2节点

  3. 输出应按姓氏排序

  4. 每个记录集最多有2条记录。

有几个技巧:

  1. 选择不同的姓氏
  2. 将姓氏记录分组
  3. 将姓氏记录分成2组
  4. 基于不同的姓氏索引创建动态元素名称

这个样式表解决了这些问题:

<?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>

相关内容

  • 没有找到相关文章

最新更新