XSLT: сценарий слияния дубликатов - PullRequest
6 голосов
/ 14 марта 2009

У меня есть такой XML

<ContractInfo  ContractNo="12345">
                <Details LastName="Goodchild">                        
                        <Filedata  FileName="File1"/>
                </Details>
</ContractInfo>

<ContractInfo  ContractNo="12345">
                <Details LastName="Goodchild">                        
                        <Filedata  FileName="File2"/>
                </Details>
</ContractInfo>

<ContractInfo  ContractNo="123456">
                <Details LastName="Goodchild">                        
                        <Filedata  FileName="File2"/>
                </Details>
</ContractInfo>

Я хочу, чтобы мой выходной XML был таким

<ContractInfo  ContractNo="12345">
                <Details LastName="Goodchild">                        
                        <Filedata  FileName="File1"/>
                        <Filedata  FileName="File2"/>
                </Details>
</ContractInfo>

<ContractInfo  ContractNo="123456">
                <Details LastName="Goodchild">                        
                        <Filedata  FileName="File2"/>
                </Details>
</ContractInfo>

Здесь, FileData, относящиеся к соответствующему «contractNo», должны быть объединены на выходе. Может ли это преобразование быть достигнуто с помощью XSLT?

Заранее спасибо.

Srini

1 Ответ

7 голосов
/ 14 марта 2009

Следующее преобразование XSLT 1.0 дает правильный результат:

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="xml" indent="yes" />

  <xsl:key name="contract" match="ContractInfo" use="@ContractNo" />
  <xsl:key name="filedata" match="Filedata" use="../../@ContractNo" />

  <xsl:template match="ContractInfo">
    <xsl:if test="generate-id() = 
                  generate-id(key('contract', @ContractNo)[1])">
      <xsl:copy>
        <xsl:apply-templates select="key('contract', @ContractNo)/Details | @*" />
      </xsl:copy>
    </xsl:if>
  </xsl:template>

  <xsl:template match="Details">
    <xsl:if test="generate-id(..) = 
                  generate-id(key('contract', ../@ContractNo)[1])">
      <xsl:copy>
        <xsl:apply-templates select="key('filedata', ../@ContractNo) | @*" />
      </xsl:copy>
    </xsl:if>
  </xsl:template>

  <!-- copy everything else (root node, Filedata nodes and @attributes) -->
  <xsl:template match="* | @*">
    <xsl:copy>
      <xsl:apply-templates select="* | @*" />
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

Обратите внимание на использование <xsl:key> в сочетании с generate-id() для идентификации первого узла соответствующего набора узлов, эффективно группируя равные узлы вместе.

Вы можете принудительно упорядочить результат, используя <xsl:sort> в пределах <xsl:apply-templates>. Я не включил это для ясности.

Мой тестовый вывод:

<root>
  <ContractInfo ContractNo="12345">
    <Details LastName="Goodchild">
      <Filedata FileName="File1"></Filedata>
      <Filedata FileName="File2"></Filedata>
    </Details>
  </ContractInfo>
  <ContractInfo ContractNo="123456">
    <Details LastName="Goodchild">
      <Filedata FileName="File2"></Filedata>
    </Details>
  </ContractInfo>
</root>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...