首页 > 解决方案 > 如何排序和获取最小开始日期(XSLT)

问题描述

我想使用 xslt 对 xml 进行排序并获取最小开始日期(删除其他)

这是我的xml

<name>
    <name>
        <firstName>Huio</firstName>
        <lastName>Kuyoshitu</lastName>
        <detail>
            <action>P</action>
            <userId>0902</userId>
            <startDate>2019-01-01T00:00:00.000</startDate>
            <endDate>2030-12-31T00:00:00.000</endDate>
        </detail>
        <detail>
            <action>P</action>
            <userId>0902</userId>
            <startDate>1990-01-01T00:00:00.000</startDate>
            <endDate>1999-12-31T00:00:00.000</endDate>
        </detail>
    </name>
</name>

我想获得最小开始日期(1990-01-01T00:00:00.000)的详细信息。

这是预期的 xml

<name>
    <name>
        <firstName>Huio</firstName>
        <lastName>Kuyoshitu</lastName>
        <detail>
            <action>P</action>
            <userId>0902</userId>
            <startDate>1990-01-01T00:00:00.000</startDate>
            <endDate>1999-12-31T00:00:00.000</endDate>
        </detail>
    </name>
</name>

我试过这段代码。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

<xsl:template match="/">
    <xsl:copy>
        <xsl:for-each-group select="name/name/detail" group-by="userId">
            <xsl:sort select='startDate' order="ascending" />
            <xsl:for-each select="current-group()">
                <xsl:sort select='startDate' order="ascending" />
                <xsl:if test="position()=1">
                    <xsl:copy-of select="."/>
                </xsl:if>
            </xsl:for-each>
        </xsl:for-each-group>
    </xsl:copy>
</xsl:template>


</xsl:stylesheet>

但名字和姓氏标签消失了。

像这样https://xsltfiddle.liberty-development.net/93dFepA

标签: xmlxsltxslt-1.0xslt-2.0

解决方案


XSLT 2 及更高版本min在序列上使用 XPath 2 功能xs:dateTime将任务减少到

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

<xsl:mode on-no-match="shallow-copy"/>

<xsl:template match="name/name">
    <xsl:copy>
        <xsl:apply-templates 
          select="let $min-date := min(detail/startDate/xs:dateTime(.))
                  return node()[not(self::detail) or self::detail[xs:dateTime(startDate) = $min-date]]"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/93dFepA/1


推荐阅读