在这个问题 ,我问如何执行有条件的增量。 所提供的答案的工作,但在庞大的数据集不能很好地扩展。
该输入:
<Users>
<User>
<id>1</id>
<username>jack</username>
</User>
<User>
<id>2</id>
<username>bob</username>
</User>
<User>
<id>3</id>
<username>bob</username>
</User>
<User>
<id>4</id>
<username>jack</username>
</User>
</Users>
所需的输出(在最佳时间复杂度):
<Users>
<User>
<id>1</id>
<username>jack01</username>
</User>
<User>
<id>2</id>
<username>bob01</username>
</User>
<User>
<id>3</id>
<username>bob02</username>
</User>
<User>
<id>4</id>
<username>jack02</username>
</User>
</Users>
为了这个目的,将是不错的
- 通过用户名输入排序
- 为每个用户
- (由ID排序再次- 不要求 )
有什么想法吗?
该变换产生准确指定的想要的结果,是高效的(O(N)):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kUserByName" match="User" use="username"/>
<xsl:key name="kUByGid" match="u" use="@gid"/>
<xsl:variable name="vOrderedByName">
<xsl:for-each select=
"/*/User[generate-id()=generate-id(key('kUserByName',username)[1])]">
<xsl:for-each select="key('kUserByName',username)">
<u gid="{generate-id()}" pos="{position()}"/>
</xsl:for-each>
</xsl:for-each>
</xsl:variable>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="username/text()">
<xsl:value-of select="."/>
<xsl:variable name="vGid" select="generate-id(../..)"/>
<xsl:for-each select="ext:node-set($vOrderedByName)[1]">
<xsl:value-of select="format-number(key('kUByGid', $vGid)/@pos, '00')"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
当应用所提供的XML文档:
<Users>
<User>
<id>1</id>
<username>jack</username>
</User>
<User>
<id>2</id>
<username>bob</username>
</User>
<User>
<id>3</id>
<username>bob</username>
</User>
<User>
<id>4</id>
<username>jack</username>
</User>
</Users>
在想,正确的结果产生:
<Users>
<User>
<id>1</id>
<username>jack01</username>
</User>
<User>
<id>2</id>
<username>bob01</username>
</User>
<User>
<id>3</id>
<username>bob02</username>
</User>
<User>
<id>4</id>
<username>jack02</username>
</User>
</Users>
这是一种丑陋,我不喜欢使用xsl:for-each
,但它应该是比使用前面的兄弟姐妹快,而且不需要2回合方法:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:key name="count" match="User" use="username" />
<xsl:template match="Users">
<Users>
<xsl:for-each select="User[generate-id()=generate-id(key('count',username)[1])]">
<xsl:for-each select="key('count',username)">
<User>
<xsl:copy-of select="id" />
<username>
<xsl:value-of select="username" />
<xsl:number value="position()" format="01"/>
</username>
</User>
</xsl:for-each>
</xsl:for-each>
</Users>
</xsl:template>
</xsl:stylesheet>
如果你真的需要它的ID进行排序后,你可以把它包装成一个双通道的模板:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<xsl:key name="count" match="User" use="username" />
<xsl:template match="Users">
<xsl:variable name="pass1">
<xsl:for-each select="User[generate-id()=generate-id(key('count',username)[1])]">
<xsl:for-each select="key('count',username)">
<User>
<xsl:copy-of select="id" />
<username>
<xsl:value-of select="username" />
<xsl:number value="position()" format="01"/>
</username>
</User>
</xsl:for-each>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="pass1Nodes" select="msxsl:node-set($pass1)" />
<Users>
<xsl:for-each select="$pass1Nodes/*">
<xsl:sort select="id" />
<xsl:copy-of select="." />
</xsl:for-each>
</Users>
</xsl:template>
</xsl:stylesheet>
这里有一个微小的变化,但可能不是在效率的大幅增长
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="xml" indent="yes"/>
<xsl:key name="User" match="User" use="username" />
<xsl:template match="username/text()">
<xsl:value-of select="." />
<xsl:variable name="id" select="generate-id(..)" />
<xsl:for-each select="key('User', .)">
<xsl:if test="generate-id(username) = $id">
<xsl:number value="position()" format="01"/>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
这是什么东西做的是定义由用户名一键组的用户。 然后,对每个用户名元素,您可以通过元素的外观在关键为该用户名和输出位置,当你找到一个匹配。
这种方法的一个微弱的优势在于,你仅仅看到具有相同名称的用户记录。 如果你没有同名巨大的数字,这可能是更有效的。