帮助XSLT转换XML:分组和选择具有最大值的元素

发布于 2024-11-03 11:39:15 字数 1514 浏览 1 评论 0 原文

我有当前的 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>

任何可以为我指明从哪里开始的正确方向的人?

提前致谢。

I have the current 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>

What I am trying to do is to filter out one element of each GUID with the highest version number, i.e, transform the document above to look like:

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

Anyone who can point me in the right direction on where to start?

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

高冷爸爸 2024-11-10 11:39:15

作为练习,我尝试使用 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>

主要区别:

As an exercise, I've tried to solve this using XSLT 2.0 and 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>

Major differences:

  • with XSLT 2.0 you don't need to define an xsl:key as in this other answer, but you can use xsl:for-each-group ... group-by="GUID"

  • with XPath 2.0 you have the fn:max(...) function

百变从容 2024-11-10 11:39:15

我首先在 GUID 上声明 key,这使得能够轻松处理不同的 GUID;然后,根据 GUID,根据 VersionNumber 对相应的 Customer 元素进行排序,并简单地复制第一个 (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> 

使用节点集的交集是处理每个不同 GUID 的第一个 Customer 的另一种方法:

<xsl:apply-templates select="//Customer[count(.|key('byGUID',GUID)[1])=1]"/>

I would start with declaring a key on GUID, this enables to easily process distinct GUIDs; then, per GUID, sort the corresponding Customer elements on their VersionNumber and simply copy the first (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> 

Using this intersection of nodesets is another way to process the first Customer for each distinct GUID:

<xsl:apply-templates select="//Customer[count(.|key('byGUID',GUID)[1])=1]"/>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文