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

XSL代码无法对SEC_Match元素按STARTEFFDATE降序排序求助

解决XSL中SEC元素转SEC_Match并按STARTEFFDATE降序排序的问题

需求概述

需将XML中**具有相同UID前缀(^符号前的部分)**的SEC元素转换为SEC_Match元素,且所有SEC_Match元素按@STARTEFFDATE属性值降序排列。

原XSL代码

<xsl:template match="*[SEC]">
    <xsl:copy>
        <xsl:apply-templates select="@*"/>
        <xsl:for-each select="*">
            <xsl:variable name="a" select="substring-before(@UID,'^')"/>
            <xsl:choose>
                <xsl:when test="self::SEC[$a = substring-before(following-sibling::SEC[1]/@UID,'^')]|self::SEC[$a = substring-before(preceding-sibling::SEC[1]/@UID,'^')]">
                    <xsl:for-each select="self::SEC[$a = substring-before(following-sibling::SEC[1]/@UID,'^')]|self::SEC[$a = substring-before(preceding-sibling::SEC[1]/@UID,'^')]">
                        <xsl:sort select="@STARTEFFDATE" data-type="number" order="descending"/>
                        <SEC_Match>
                            <xsl:apply-templates select="@*"/>
                            <xsl:apply-templates/>
                        </SEC_Match>
                    </xsl:for-each>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:copy>
                        <xsl:apply-templates select="@* | node()"/>
                    </xsl:copy>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>

输入XML

<LEVEL2 UID="XXXX" CAPTION="CH" D="381" PRIOR="NO" MEDIA="ALL">
    <NAME>Public Health: </NAME>

    <SEC D="3-4-218" UID="ar3-4-218^XXXX" STARTEFFDATE="20171001">
        <NAME> permitted premises</NAME>
        <SBSEC D="(a)" LOC="3-4-218(a)" ANCHOR="3-4-218(a)" PERIOD="0" PRIOR="NO">
            <P> test test </P>
        </SBSEC>
    </SEC>

    <SEC D="381.986" UID="fl381.986^XXXXX" STARTEFFDATE="600"
        >
        <NAME>Medical use of marijuana</NAME>
        <SBSEC D="(1)" LOC="381.986(1)" ANCHOR="381.986(1)" PERIOD="0" PRIOR="NO">
            <P>who has agreed to assist</P>
        </SBSEC>
    </SEC>

    <SEC D="381.986" UID="fl381.986^XXXX" STARTEFFDATE="200">
        <NAME>Medical use of marijuana</NAME>
        <SBSEC D="(1)" LOC="381.986(1)" ANCHOR="381.986(1)" PERIOD="0" PRIOR="NO">
            <P> &#8220;Attractive to children&#8221;</P>
        </SBSEC>
    </SEC>

    <SEC D="381.986" UID="fl381.986^XXXX" STARTEFFDATE="800">
        <NAME>Medical use of marijuana</NAME>
        <SBSEC D="(1)" LOC="381.986(1)" ANCHOR="381.986(1)" PERIOD="0" PRIOR="NO">
            <P> &#8220;Attractive to children&#8221; means the use of any image or words</P>
        </SBSEC>
    </SEC>

    <SEC D="3-4-218" UID="ar3-4-218^XXXXX" STARTEFFDATE="20171001">
        <NAME>Permits restricted to permitted premises</NAME>
        <SBSEC D="(a)" LOC="3-4-218(a)" ANCHOR="3-4-218(a)" PERIOD="0" PRIOR="NO">
            <P>goods, dry goods, hardware, or general mercantile store. </P>
        </SBSEC>
    </SEC>

    <SEC D="381.986" UID="fl381.986^XXXXX" STARTEFFDATE="100">
        <NAME>Medical use of marijuana</NAME>
        <SBSEC D="(1)" LOC="381.986(1)" ANCHOR="381.986(1)" PERIOD="0" PRIOR="NO">
            <P>identification card, and meets the requirements of subsection (6). </P>
        </SBSEC>
    </SEC>
</LEVEL2>

当前输出XML

<LEVEL2 UID="XXXX" CAPTION="CH" D="381" PRIOR="NO" MEDIA="ALL">
<NAME>Public Health: </NAME>
<SEC D="3-4-218" UID="ar3-4-218^XXXX" STARTEFFDATE="20171001">
    <NAME> permitted premises</NAME>
    <SBSEC D="(a)" LOC="3-4-218(a)" ANCHOR="3-4-218(a)" PERIOD="0" PRIOR="NO">
        <P> test test </P>
    </SBSEC>
</SEC>
<SEC_Match D="381.986" UID="fl381.986^XXXXX" STARTEFFDATE="600">
    <NAME>Medical use of marijuana</NAME>
    <SBSEC D="(1)" LOC="381.986(1)" ANCHOR="381.986(1)" PERIOD="0" PRIOR="NO">
        <P>who has agreed to assist</P>
    </SBSEC>
</SEC_Match>
<SEC_Match D="381.986" UID="fl381.986^XXXX" STARTEFFDATE="200">
    <NAME>Medical use of marijuana</NAME>
    <SBSEC D="(1)" LOC="381.986(1)" ANCHOR="381.986(1)" PERIOD="0" PRIOR="NO">
        <P> “Attractive to children”</P>
    </SBSEC>
</SEC_Match>
<SEC_Match D="381.986" UID="fl381.986^XXXX" STARTEFFDATE="800">
    <NAME>Medical use of marijuana</NAME>
    <SBSEC D="(1)" LOC="381.986(1)" ANCHOR="381.986(1)" PERIOD="0" PRIOR="NO">
        <P> “Attractive to children” means the use of any image or words</P>
    </SBSEC>
</SEC_Match>
<SEC D="3-4-218" UID="ar3-4-218^XXXXX" STARTEFFDATE="20171001">
    <NAME>Permits restricted to permitted premises</NAME>
    <SBSEC D="(a)" LOC="3-4-218(a)" ANCHOR="3-4-218(a)" PERIOD="0" PRIOR="NO">
        <P>goods, dry goods, hardware, or general mercantile store. </P>
    </SBSEC>
</SEC>
<SEC D="381.986" UID="fl381.986^XXXXX" STARTEFFDATE="100">
    <NAME>Medical use of marijuana</NAME>
    <SBSEC D="(1)" LOC="381.986(1)" ANCHOR="381.986(1)" PERIOD="0" PRIOR="NO">
        <P>identification card, and meets the requirements of subsection (6). </P>
    </SBSEC>
</SEC>
</LEVEL2>

问题分析

原代码存在以下缺陷:

  1. 分组逻辑错误:仅通过相邻节点判断是否属于同组,导致同UID前缀但不相邻的SEC被遗漏(如最后一个STARTEFFDATE=100的SEC未被转换为SEC_Match)。
  2. 排序范围过小:内部xsl:for-each仅选择当前节点及单个相邻匹配节点,无法覆盖同组所有SEC,排序仅对局部节点生效。
  3. 遍历方式低效:逐个处理子节点,重复判断分组,容易出现遗漏和重复输出。

修正后的XSL代码(XSLT 1.0)

采用Muenchian分组实现按UID前缀分组,再对每组内节点排序:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <!-- 定义键:按UID前缀分组 -->
    <xsl:key name="secByUidPrefix" match="SEC" use="substring-before(@UID, '^')"/>

    <!-- 复制所有节点的默认模板 -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!-- 匹配包含SEC的父节点(如LEVEL2) -->
    <xsl:template match="*[SEC]">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <!-- 先处理非SEC节点 -->
            <xsl:apply-templates select="*[not(self::SEC)]"/>
            <!-- 处理SEC分组:仅选择每组的第一个节点作为代表 -->
            <xsl:for-each select="SEC[generate-id() = generate-id(key('secByUidPrefix', substring-before(@UID, '^'))[1])]">
                <xsl:variable name="prefix" select="substring-before(@UID, '^')"/>
                <!-- 遍历同组所有SEC,按STARTEFFDATE降序排序 -->
                <xsl:for-each select="key('secByUidPrefix', $prefix)">
                    <xsl:sort select="@STARTEFFDATE" data-type="number" order="descending"/>
                    <SEC_Match>
                        <xsl:apply-templates select="@*|node()"/>
                    </SEC_Match>
                </xsl:for-each>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

期望输出XML

<LEVEL2 UID="XXXX" CAPTION="CH" D="381" PRIOR="NO" MEDIA="ALL">
    <NAME>Public Health: </NAME>
    <SEC_Match D="3-4-218" UID="ar3-4-218^XXXX" STARTEFFDATE="20171001">
        <NAME> permitted premises</NAME>
        <SBSEC D="(a)" LOC="3-4-218(a)" ANCHOR="3-4-218(a)" PERIOD="0" PRIOR="NO">
            <P> test test </P>
        </SBSEC>
    </SEC_Match>
    <SEC_Match D="3-4-218" UID="ar3-4-218^XXXXX" STARTEFFDATE="20171001">
        <NAME>Permits restricted to permitted premises</NAME>
        <SBSEC D="(a)" LOC="3-4-218(a)" ANCHOR="3-4-218(a)" PERIOD="0" PRIOR="NO">
            <P>goods, dry goods, hardware, or general mercantile store. </P>
        </SBSEC>
    </SEC_Match>
    <SEC_Match D="381.986" UID="fl381.986^XXXX" STARTEFFDATE="800">
        <NAME>Medical use of marijuana</NAME>
        <SBSEC D="(1)" LOC="381.986(1)" ANCHOR="381.986(1)" PERIOD="0" PRIOR="NO">
            <P> “Attractive to children” means the use of any image or words</P>
        </SBSEC>
    </SEC_Match>
    <SEC_Match D="381.986" UID="fl381.986^XXXXX" STARTEFFDATE="600">
        <NAME>Medical use of marijuana</NAME>
        <SBSEC D="(1)" LOC="381.986(1)" ANCHOR="381.986(1)" PERIOD="0" PRIOR="NO">
            <P>who has agreed to assist</P>
        </SBSEC>
    </SEC_Match>
    <SEC_Match D="381.986" UID="fl381.986^XXXX" STARTEFFDATE="200">
        <NAME>Medical use of marijuana</NAME>
        <SBSEC D="(1)" LOC="381.986(1)" ANCHOR="381.986(1)" PERIOD="0" PRIOR="NO">
            <P> “Attractive to children”</P>
        </SBSEC>
    </SEC_Match>
    <SEC_Match D="381.986" UID="fl381.986^XXXXX" STARTEFFDATE="100">
        <NAME>Medical use of marijuana</NAME>
        <SBSEC D="(1)" LOC="381.986(1)" ANCHOR="381.986(1)" PERIOD="0" PRIOR="NO">
            <P>identification card, and meets the requirements of subsection (6). </P>
        </SBSEC>
    </SEC_Match>
</LEVEL2>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 20:05:54