You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用XSLT合并XML中job属性与login值相同的ban元素并取最新reason

没问题,我来帮你搞定这个XSLT合并需求!核心思路是按job属性和login元素的组合值分组,然后在每组里提取最新的reason值。下面分情况给出实现方案:

先看示例输入XML

假设你的原始XML结构是这样的(对应你描述的5个ban元素场景):

<root>
  <ban job="gh:test/test#1">
    <login>user1</login>
    <reason>First ban reason for user1</reason>
    <date>2023-01-01</date>
  </ban>
  <ban job="gh:test/test#1">
    <login>user1</login>
    <reason>Updated ban reason for user1</reason>
    <date>2023-02-01</date>
  </ban>
  <ban job="gh:test/test#2">
    <login>user2</login>
    <reason>Initial ban for user2</reason>
    <date>2023-01-15</date>
  </ban>
  <ban job="gh:test/test#3">
    <login>user3</login>
    <reason>One-time ban for user3</reason>
    <date>2023-03-01</date>
  </ban>
  <ban job="gh:test/test#2">
    <login>user2</login>
    <reason>Latest ban reason for user2</reason>
    <date>2023-03-15</date>
  </ban>
</root>

方案1:XSLT 2.0/3.0(推荐,语法更简洁)

利用xsl:for-each-group直接分组,同时支持按日期取最新(如果有日期字段)或按节点顺序取最后一个:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <!-- 定义分组键:job属性 + login值,用|分隔避免冲突 -->
  <xsl:key name="ban-group" match="ban" use="concat(@job, '|', login)"/>

  <xsl:template match="/root">
    <root>
      <!-- 按组合键分组遍历 -->
      <xsl:for-each-group select="ban" group-by="concat(@job, '|', login)">
        <ban job="{@job}">
          <!-- 每组的login值都相同,直接取第一个即可 -->
          <login><xsl:value-of select="login"/></login>
          <!-- 方式1:按日期取最新的reason(推荐,更精准) -->
          <xsl:variable name="latest-by-date" select="current-group()[date = max(current-group()/date)]"/>
          <reason><xsl:value-of select="$latest-by-date/reason"/></reason>
          <date><xsl:value-of select="$latest-by-date/date"/></date>

          <!-- 方式2:如果没有日期,按节点顺序取最后一个的reason -->
          <!-- <reason><xsl:value-of select="current-group()[last()]/reason"/></reason> -->
        </ban>
      </xsl:for-each-group>
    </root>
  </xsl:template>
</xsl:stylesheet>

方案2:XSLT 1.0(兼容旧环境)

如果只能用XSLT 1.0,就用Muenchian分组实现,代码稍复杂但逻辑一致:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:key name="ban-group" match="ban" use="concat(@job, '|', login)"/>

  <xsl:template match="/root">
    <root>
      <!-- 选择每组的第一个节点作为分组入口 -->
      <xsl:for-each select="ban[generate-id() = generate-id(key('ban-group', concat(@job, '|', login))[1])]">
        <xsl:variable name="current-group" select="key('ban-group', concat(@job, '|', login))"/>
        <ban job="{@job}">
          <login><xsl:value-of select="login"/></login>
          <!-- 按节点顺序取最后一个的reason -->
          <reason><xsl:value-of select="$current-group[last()]/reason"/></reason>

          <!-- 如果要按日期取最新,需要先排序再取第一个 -->
          <!-- <xsl:for-each select="$current-group">
            <xsl:sort select="date" order="descending"/>
            <xsl:if test="position() = 1">
              <reason><xsl:value-of select="reason"/></reason>
              <date><xsl:value-of select="date"/></date>
            </xsl:if>
          </xsl:for-each> -->
        </ban>
      </xsl:for-each>
    </root>
  </xsl:template>
</xsl:stylesheet>

预期输出

无论用哪种方案,最终都会得到合并后的XML,比如:

<root>
  <ban job="gh:test/test#1">
    <login>user1</login>
    <reason>Updated ban reason for user1</reason>
    <date>2023-02-01</date>
  </ban>
  <ban job="gh:test/test#2">
    <login>user2</login>
    <reason>Latest ban reason for user2</reason>
    <date>2023-03-15</date>
  </ban>
  <ban job="gh:test/test#3">
    <login>user3</login>
    <reason>One-time ban for user3</reason>
    <date>2023-03-01</date>
  </ban>
</root>

关键说明

  • 分组键用concat(@job, '|', login)是为了避免不同job和login的组合产生冲突(比如job="a|b"+login="c"和job="a"+login="b|c"的情况)
  • 如果你没有date字段,直接用节点顺序取最后一个元素的reason即可,也就是代码里注释掉的方式2

内容的提问来源于stack exchange,提问作者Kirill

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 09:06:53