2016-01-08 45 views
0

我需要一个可转换以下XML的XSLT 1.0。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> 

我期待的输出是:

<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. Recordset1应该包含Surname1节点

  2. Recordset2应该包含Surname2节点

  3. 输出结果应按姓氏排序

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

回答

0

这可能对你有所帮助。

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

你想象究竟是什么这样做:'的'? –

+1

这是您之前向我指出的Muenchian方法。我只是简化了它的每个部分,如下所示:对于每个行Surname,找到具有该姓的第一个Row实例。所以,如果当前的行是第一个实例,那么做东西。很好的问题。顺便说一句,这段代码工作得很好。 – Bluewood66

+0

“*对于每个行姓可以找到第一个具有该姓氏的Row实例。*”这不是您的“简化”。它查找**的整个文本值**等于具有该姓氏的第一个Row实例的文本值的每一行。这很容易导致重复。 –

0

有一些技巧,以这样的:

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

这不是一个好的答案 - 看到这里为什么:http://www.jenitennison.com/xslt/grouping/muenchian.html –

+0

@ michael.hor257k你是对的,它是一个很好的答案,因为它解决了给定的问题,同时划分@罗兰德遇到的不同问题。如果您担心'prior'的使用对于确定不同值的效率太低,则可以在第一个模板中轻松地替换另一种方法。 – vallismortis