Помощь с XSLT для преобразования XML: группировка и выбор элементов с максимальным значением - PullRequest
0 голосов
/ 28 апреля 2011

У меня есть текущий XML:

<DocumentElement>
  <Customer>
    <CustomerId>2315</CustomerId>
    <Date>2011-04-28 14:14:00</Date>   
    <VersionNumber>1</VersionNumber>
    <GUID>2E05DE20-02A0-425D-944D-65E5E744FF8A</GUID>
  </Customer>
  <Customer>
    <CustomerId>2316</CustomerId>
    <Date>2011-04-28 15:03:00</Date>
    <VersionNumber>2</VersionNumber>
    <GUID>2E05DE20-02A0-425D-944D-65E5E744FF8A</GUID>
  </Customer>
  <Customer>
    <CustomerId>2317</CustomerId>
    <Date>2011-04-28 15:03:00</Date>
    <VersionNumber>1</VersionNumber>
    <GUID>9995DE20-02A0-425D-944D-65E5E744FF8A</GUID>
  </Customer>
</DocumentElement>

То, что я пытаюсь сделать, это отфильтровать один элемент каждого GUID с наибольшим номером версии, то есть преобразовать документ, приведенный выше, в следующий вид:

<DocumentElement>
  <Customer>
    <CustomerId>2316</CustomerId>
    <Date>2011-04-28 15:03:00</Date>
    <VersionNumber>2</VersionNumber>
    <GUID>2E05DE20-02A0-425D-944D-65E5E744FF8A</GUID>
  </Customer>
  <Customer>
    <CustomerId>2317</CustomerId>
    <Date>2011-04-28 15:03:00</Date>
    <VersionNumber>1</VersionNumber>
    <GUID>9995DE20-02A0-425D-944D-65E5E744FF8A</GUID>
  </Customer>
</DocumentElement>

Кто-нибудь, кто может указать мне в правильном направлении, с чего начать?

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

Ответы [ 2 ]

2 голосов
/ 28 апреля 2011

В качестве упражнения я попытался решить эту проблему с помощью XSLT 2.0 и XPath 2.0:

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

  <xsl:output method="xml" indent="yes" omit-xml-declaration="no" />

  <xsl:template match="/DocumentElement">
   <xsl:copy>
    <xsl:for-each-group select="Customer" group-by="GUID">
     <xsl:copy-of select="current-group()
                          [VersionNumber=max(current-group()/VersionNumber)]" />
    </xsl:for-each-group>
   </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

Основные различия:

  • с XSLT 2.0 вам не нужно определять xsl:key как в этом другом ответе , но вы можете использовать xsl:for-each-group ... group-by="GUID"

  • с XPath 2.0 у вас есть функция fn:max(...)

1 голос
/ 28 апреля 2011

Я бы начал с объявления ключа на GUID, это позволяет легко обрабатывать различные GUID;затем по GUID сортируйте соответствующие элементы Customer по их VersionNumber и просто скопируйте первый (xslt-1.0):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
    <xsl:key name="byGUID" match="Customer" use="GUID"/>
    <xsl:template match="/*">
        <xsl:copy>
            <!-- process first Customer for each distinct GUID -->
            <xsl:apply-templates select="//Customer[generate-id()=generate-id(key('byGUID',GUID))]"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*">
        <!-- sort and process all Customers with the same GUID -->
        <xsl:apply-templates select="key('byGUID',GUID)" mode="copyFirst">
            <xsl:sort select="VersionNumber" order="descending"/>
        </xsl:apply-templates>
    </xsl:template>
    <xsl:template match="*" mode="copyFirst">
        <!-- only copy the first (highest VersionNumber) -->
        <xsl:if test="position()=1">
            <xsl:copy-of select="."/>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet> 

Использование такого пересечения наборов узлов - это еще один способ обработки первого Customer для каждого отдельного GUID.:

<xsl:apply-templates select="//Customer[count(.|key('byGUID',GUID)[1])=1]"/>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...