英文:
Get max date from each specific user ID without repeating IDs using XSLT
问题
您想提取每个用户的最大日期,并在结果中显示如下格式:
<?xml version="1.0" encoding="UTF-8"?>
<LastModified>15/3/2023</LastModified>
<User>5</User>
您已经创建了XSLT样式表,但遇到了重复的问题。要解决这个问题,您可以使用XSLT以一种更精细的方式处理数据,如下所示:
<?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="user-key" match="Record" use="User"/>
<xsl:template match="/root">
<xsl:for-each select="Data/Record[generate-id() = generate-id(key('user-key', User)[1])]">
<xsl:variable name="currentUser" select="User"/>
<xsl:for-each select="key('user-key', $currentUser)">
<xsl:sort select="concat(substring(LastModified, 7, 4), substring(LastModified, 4, 2), substring(LastModified, 1, 2))"
data-type="number" order="descending"/>
<xsl:if test="position() = 1">
<LastModified>
<xsl:value-of select="LastModified"/>
</LastModified>
<User>
<xsl:value-of select="User"/>
</User>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
这个XSLT样式表将为每个用户提取最大日期,而不会产生重复结果。
英文:
I have the following XML
<?xml version='1.0' encoding='UTF-8'?>
<root>
<Data>
<Record>
<User>1</User>
<LastModified>1/1/2023</LastModified>
<UniversityDegree>University of Texas Bachelors</UniversityDegree>
</Record>
<Record>
<User>1</User>
<LastModified>1/11/2023</LastModified>
<UniversityDegree>University of Missouri Masters</UniversityDegree>
</Record>
<Record>
<User>2</User>
<LastModified>1/1/2024</LastModified>
<UniversityDegree>University of Texas Bachelors</UniversityDegree>
</Record>
<Record>
<User>2</User>
<LastModified>1/12/2023</LastModified>
<UniversityDegree>University of Missouri Masters</UniversityDegree>
</Record>
<Record>
<User>3</User>
<LastModified>5/7/2023</LastModified>
<UniversityDegree>University of Texas Bachelors</UniversityDegree>
</Record>
<Record>
<User>3</User>
<LastModified>9/8/2023</LastModified>
<UniversityDegree>University of Missouri Masters</UniversityDegree>
</Record>
<Record>
<User>4</User>
<LastModified>24/1/2023</LastModified>
<UniversityDegree>University of Texas Bachelors</UniversityDegree>
</Record>
<Record>
<User>4</User>
<LastModified>28/9/2023</LastModified>
<UniversityDegree>University of Missouri Masters</UniversityDegree>
</Record>
<Record>
<User>5</User>
<LastModified>15/3/2023</LastModified>
<UniversityDegree>University of Texas Bachelors</UniversityDegree>
</Record>
<Record>
<User>5</User>
<LastModified>10/3/2023</LastModified>
<UniversityDegree>University of Missouri Masters</UniversityDegree>
</Record>
</Data>
</root>
And I need to extract the max date of each user, so for example out of use 5 the max date from 15/3/2023 and 10/3/2023 is 15/3/2023 and show it like this:
<?xml version="1.0" encoding="UTF-8"?>
<LastModified>15/3/2023</LastModified>
<User>5</User>
I've done the following,
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="//root">
<xsl:for-each select="//Record">
<xsl:sort select="number(substring(LastModified, 7, 4))" order="descending"/>
<xsl:sort select="number(substring(LastModified, 3, 2))" order="descending"/>
<xsl:sort select="number(substring(LastModified, 1, 2))" order="descending"/>
<xsl:if test="position() = 1">
<xsl:copy-of select="LastModified"/>
<xsl:copy-of select="User"/>
<Source>SF</Source>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Which returns,
<?xml version="1.0" encoding="UTF-8"?>
<LastModified>1/1/2024</LastModified>
<User>2</User>
<Source>SF</Source>
But it only returns the first sorted record due to the position 1 if. I would need to get the max date of each of the users without having duplicates. If I remove the IF condition, I get everything sorted but Users are repeated,
<?xml version="1.0" encoding="UTF-8"?>
<LastModified>1/1/2024</LastModified>
<User>2</User>
<Source>SF</Source>
<LastModified>1/12/2023</LastModified>
<User>2</User>
<Source>SF</Source>
<LastModified>1/11/2023</LastModified>
<User>1</User>
<Source>SF</Source>
<LastModified>28/9/2023</LastModified>
<User>4</User>
<Source>SF</Source>
<LastModified>24/1/2023</LastModified>
<User>4</User>
<Source>SF</Source>
<LastModified>15/3/2023</LastModified>
<User>5</User>
<Source>SF</Source>
<LastModified>10/3/2023</LastModified>
<User>5</User>
<Source>SF</Source>
<LastModified>1/1/2023</LastModified>
<User>1</User>
<Source>SF</Source>
<LastModified>5/7/2023</LastModified>
<User>3</User>
<Source>SF</Source>
<LastModified>9/8/2023</LastModified>
<User>3</User>
<Source>SF</Source>
答案1
得分: 0
以下是您提供的代码的翻译:
尝试使用如下的方式:
**XSLT 2.0**
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/root">
<result>
<xsl:for-each-group select="Data/Record" group-by="User">
<user>
<xsl:for-each select="current-group()">
<xsl:sort select="tokenize(LastModified, '/')" data-type="number" order="descending"/>
<xsl:sort select="tokenize(LastModified, '/')[2]" data-type="number" order="descending"/>
<xsl:sort select="tokenize(LastModified, '/')[1]" data-type="number" order="descending"/>
<xsl:if test="position() = 1">
<xsl:copy-of select="LastModified, User"/>
<Source>SF</Source>
</xsl:if>
</xsl:for-each>
</user>
</xsl:for-each-group>
</result>
</xsl:template>
</xsl:stylesheet>
请注意:这个翻译是提供给您参考的代码的XML表示,未进行详细测试。
英文:
Try perhaps something like:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/root">
<result>
<xsl:for-each-group select="Data/Record" group-by="User">
<user>
<xsl:for-each select="current-group()">
<xsl:sort select="tokenize(LastModified, '/')[3]" data-type="number" order="descending"/>
<xsl:sort select="tokenize(LastModified, '/')[2]" data-type="number" order="descending"/>
<xsl:sort select="tokenize(LastModified, '/')[1]" data-type="number" order="descending"/>
<xsl:if test="position() = 1">
<xsl:copy-of select="LastModified, User"/>
<Source>SF</Source>
</xsl:if>
</xsl:for-each>
</user>
</xsl:for-each-group>
</result>
</xsl:template>
</xsl:stylesheet>
Caveat: not tested very thoroughly.
答案2
得分: 0
以下是一个稍微不同的方法,不一定更好,但它利用了更多的XSLT 2.0特性:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://www.example.com/mf"
exclude-result-prefixes="xs mf">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/root">
<result>
<xsl:for-each-group select="Data/Record" group-by="User">
<user>
<LastModified>
<xsl:value-of select="format-date(max(current-group()/LastModified/mf:reformat-date(.)), '[D]/[M]/[Y]')"/>
</LastModified>
<xsl:copy-of select="User"/>
<Source>SF</Source>
</user>
</xsl:for-each-group>
</result>
</xsl:template>
<xsl:function name="mf:reformat-date" as="xs:date">
<!-- 期望的输入格式: d/m/y -->
<xsl:param name="date"/>
<xsl:variable name="components" select="for $t in tokenize($date, '/') return xs:integer($t)" />
<xsl:value-of select="format-number($components[3], '0000'), format-number($components[2], '00'), format-number($components[1], '00')" separator="-"/>
</xsl:function>
</xsl:stylesheet>
英文:
Here is a somewhat different approach that's not necessarily better, but it takes advantage of more XSLT 2.0 features:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://www.example.com/mf"
exclude-result-prefixes="xs mf">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/root">
<result>
<xsl:for-each-group select="Data/Record" group-by="User">
<user>
<LastModified>
<xsl:value-of select="format-date(max(current-group()/LastModified/mf:reformat-date(.)), '[D]/[M]/[Y]')"/>
</LastModified>
<xsl:copy-of select="User"/>
<Source>SF</Source>
</user>
</xsl:for-each-group>
</result>
</xsl:template>
<xsl:function name="mf:reformat-date" as="xs:date">
<!-- expected input format: d/m/y -->
<xsl:param name="date"/>
<xsl:variable name="components" select="for $t in tokenize($date, '/') return xs:integer($t)" />
<xsl:value-of select="format-number($components[3], '0000'), format-number($components[2], '00'), format-number($components[1], '00')" separator="-"/>
</xsl:function>
</xsl:stylesheet>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论