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