Найти максимальное значение всех дочерних элементов и получить только максимальную строку этого дочернего элемента с помощью преобразования xsl 1.0

#xslt

#xslt

Вопрос:

Например, исходный xml является

 <records>
    <record>
        <personId>111</personId>
        <location>Australia</location>
        <year>1999</year>
    </record>
    <record>
        <personId>222</personId>
        <location>Netherland</location>
        <year>1919</year>
    </record>
    <record>
        <personId>111</personId>
        <location>USA</location>
        <year>2000</year>
    </record>
</records>
  

теперь после xsl это должно быть что-то вроде приведенного ниже, где он берет последний год (максимум для elemtnt year) и отбрасывает старые записи для этого PersonID:

 <records>
    <record>
        <personId>222</personId>
        <location>Netherland</location>
        <year>1919</year>
    </record>
    <record>
        <personId>111</personId>
        <location>USA</location>
        <year>2000</year>
    </record>
</records>
  

Ответ №1:

Эта таблица стилей:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="kRecordByPersonId" match="record" use="personId"/>
    <xsl:template match="node()|@*" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="record"/>
    <xsl:template match="record[count(.|key('kRecordByPersonId',personId)[1])
                                 = 1]">
        <xsl:for-each select="key('kRecordByPersonId',personId)">
            <xsl:sort select="year" data-type="number" order="descending"/>
            <xsl:if test="position()=1">
                <xsl:call-template name="identity"/>
            </xsl:if>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>
  

Вывод:

 <records>
    <record>
        <personId>111</personId>
        <location>USA</location>
        <year>2000</year>
    </record>
    <record>
        <personId>222</personId>
        <location>Netherland</location>
        <year>1919</year>
    </record>
</records>
  

Просто для развлечения, сохраняя порядок исходных данных, но также хорошую производительность:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="kRecordByPersonId" match="record" use="personId"/>
    <xsl:template match="node()|@*" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="records">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:call-template name="group-max">
                <xsl:with-param name="pGroup"
                 select="record[count(.|key('kRecordByPersonId',personId)[1])
                                 = 1]"/>
            </xsl:call-template>
        </xsl:copy>
    </xsl:template>
    <xsl:template name="group-max">
        <xsl:param name="pGroup" select="/.."/>
        <xsl:param name="pGroup-Max" select="/.."/>
        <xsl:choose>
            <xsl:when test="$pGroup">
                <xsl:for-each
                 select="key('kRecordByPersonId',$pGroup[1]/personId)">
                    <xsl:sort select="year"
                              data-type="number"
                              order="descending"/>
                    <xsl:if test="position()=1">
                        <xsl:call-template name="group-max">
                            <xsl:with-param name="pGroup"
                             select="$pGroup[position()!=1]"/>
                            <xsl:with-param name="pGroup-Max"
                             select="$pGroup-Max|."/>
                        </xsl:call-template>
                    </xsl:if>
                </xsl:for-each>
            </xsl:when>
            <xsl:otherwise>
                <xsl:apply-templates select="$pGroup-Max"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>
  

Вывод:

 <records>
    <record>
        <personId>222</personId>
        <location>Netherland</location>
        <year>1919</year>
    </record>
    <record>
        <personId>111</personId>
        <location>USA</location>
        <year>2000</year>
    </record>
</records>