简体   繁体   English

XSLT 1.0对XML进行排序和分组

[英]XSLT 1.0 to sort and group an XML

I need an XSLT 1.0 that converts the following XML. 我需要一个XSLT 1.0,它可以转换以下XML。

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

The output I am expecting is: 我期望的输出是:

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

The conditions are: 条件是:

  1. Recordset1 should contain Surname1 nodes Recordset1应包含Surname1节点

  2. Recordset2 should contain Surname2 nodes Recordset2应包含Surname2节点

  3. Output should be sorted by Surname 输出应按姓氏排序

  4. There is a maximum of 2 Records per Recordset. 每个记录集最多有2条记录。

This may help you. 这可能对您有帮助。

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

There were a few tricks to this: 有一些技巧:

  1. Select distinct surnames. 选择不同的姓。
  2. Group the surname records. 分组姓氏记录。
  3. Subset the surname records in groups of 2. 将姓氏记录分成2组。
  4. Create dynamic element names based on the distinct surname index. 根据不同的姓氏索引创建动态元素名称。

This stylesheet solves those problems: 此样式表解决了这些问题:

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

The output of applying this stylesheet against your input document is: 对您的输入文档应用此样式表的输出为:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM