我有这两个xmls 1 GT; default.xml中
<UI-defination>
<class >
<list_view >
<members>
<member col_span="1" name="code" displayName="Code"/>
<member col_span="1" name="creationTS" displayName="CreationTS"/>
<member col_span="1" name="creator" displayName="Creator"/>
<member col_span="1" name="displayName" displayName="DisplayName"/>
<member col_span="1" name="emailAddress" displayName="EmailAddress"/>
<member col_span="1" name="id" displayName="Id"/>
</members>
</list_view>
</class>
</UI-defination>
2 - ; Rules.xml中
<UI-defination>
<class name="Role">
<list_view multiselect="true">
<members>
<member name="displayName" sequence="3"/>
<member name="code" sequence="4"/>
</members>
<exclude>
<members>
<member name="id"/>
<member name="creator"/>
</members>
</exclude>
</list_view>
</class>
</UI-defination>
我想按照以下规则显示会员元素的列表
答案 0 :(得分:3)
恕我直言,这不是排序问题,而是排队问题 让我们通过拥有两种类型的成员来简化示例:放置成员,保留队列中的位置,以及需要填补放置成员之间间隙的普通成员。然后是具有序列attr的元素,它们应该在那个 确切的位置。然后空洞位置应该被自然填充 剩余元素的顺序(即由没有元素的元素 序列attr。,来自default.xml)
<members>
<member id="1" place="9"/>
<member id="2" place="2"/>
<member id="3" place="5"/>
<member id="4"/>
<member id="5"/>
<member id="6"/>
<member id="7"/>
<member id="8"/>
<member id="9"/>
<member id="10"/>
<member id="11"/>
<member id="12"/>
</members>
排队算法可以描述如下:
保留成员按其保留位置排序。
每个预留成员“召集”一组普通成员坐在它前面。
在我们的例子中,我们在第2,5和9位保留了成员。之前 将预留成员安置在第9位,我们需要召集一组3人 普通会员在6,7和8号就座。
这个组的大小等于之间的差距大小 当前成员的保留地和前面的地方 保留的兄弟姐妹。在我们的例子中,这是9 - 5 - 1 = 3。
该小组的起始位置可以推断如下:因为 前面成员的预留位置是#5,然后是5个成员 已经坐了其中2名成员(地点#2和#5) 是保留会员,因此只有3名普通会员 坐下,我们的小组从5 - 3 + 1 = 4开始。
最后一个保留成员将其余的普通成员召集到其后。
以下是XSLT 1.0中的实现示例:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:variable name="reserved-members">
<xsl:for-each select="/members/member[@place]">
<xsl:sort select="@place" data-type="number" order="ascending"/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="ordinary-members" select="/members/member[not(@place)]"/>
<xsl:template match="/">
<output>
<xsl:for-each select="exsl:node-set($reserved-members)/member">
<xsl:variable name="previous-place">
<xsl:choose>
<xsl:when test="position()>1">
<xsl:value-of select="preceding-sibling::member[1]/@place"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="0"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="gap-size" select="@place - $previous-place - 1"/>
<xsl:variable name="gap-start" select="$previous-place - count(preceding-sibling::member) + 1"/>
<!-- fill the gap with ordinary members -->
<xsl:for-each select="$ordinary-members[$gap-start <= position() and position() < $gap-start + $gap-size]">
<xsl:copy-of select="."/>
</xsl:for-each>
<!-- output the reserved member -->
<member id="{@id}" place="{@place}" start="{$gap-start}" size="{$gap-size}"/>
<!-- output remaining ordinary members -->
<xsl:if test="position()=last()">
<xsl:for-each select="$ordinary-members[position() >= $gap-start + $gap-size]">
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:if>
</xsl:for-each>
</output>
</xsl:template>
</xsl:stylesheet>
当应用于上述输入示例时,结果为:
<?xml version="1.0" encoding="UTF-8"?>
<output>
<member id="4"/>
<member id="2" place="2" start="1" size="1"/>
<member id="5"/>
<member id="6"/>
<member id="3" place="5" start="2" size="2"/>
<member id="7"/>
<member id="8"/>
<member id="9"/>
<member id="1" place="9" start="4" size="3"/>
<member id="10"/>
<member id="11"/>
<member id="12"/>
</output>
答案 1 :(得分:1)
以下假设您只想输出member
元素,它使用递归函数从原始元素构造正确的序列,使用在rules.xml中定义位置的元素或用下一个剩余元素填充该位置:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs mf"
xmlns:mf="http://example.com/mf">
<xsl:param name="rules-uri" select="'Rules.xml'"/>
<xsl:variable name="rules-doc" select="doc($rules-uri)"/>
<xsl:variable name="main-input" select="/"/>
<xsl:output indent="yes"/>
<xsl:key name="member" match="list_view/members/member" use="@name"/>
<xsl:key name="pos" match="list_view/members/member" use="xs:integer(@sequence)"/>
<xsl:variable name="exclude" select="key('member', $rules-doc//exclude/members/member/@name)"/>
<xsl:variable name="process" select="//list_view/members/member except $exclude"/>
<xsl:variable name="no-key" select="$process[not(key('member', @name, $rules-doc))]"/>
<xsl:function name="mf:fill" as="element(member)*">
<xsl:param name="pos" as="xs:integer"/>
<xsl:param name="length" as="xs:integer"/>
<xsl:param name="no-key" as="element(member)*"/>
<xsl:sequence select="if ($pos gt $length)
then ()
else
(if (key('pos', $pos, $rules-doc))
then (key('member', key('pos', $pos, $rules-doc)/@name, $main-input),
mf:fill($pos + 1, $length, $no-key))
else ($no-key[1], mf:fill($pos + 1, $length, $no-key[position() gt 1])))"/>
</xsl:function>
<xsl:template match="/">
<xsl:sequence select="mf:fill(1, count($process), $no-key)"/>
</xsl:template>
</xsl:stylesheet>
输入为
<UI-defination>
<class >
<list_view >
<members>
<member col_span="1" name="code" displayName="Code"/>
<member col_span="1" name="creationTS" displayName="CreationTS"/>
<member col_span="1" name="creator" displayName="Creator"/>
<member col_span="1" name="displayName" displayName="DisplayName"/>
<member col_span="1" name="emailAddress" displayName="EmailAddress"/>
<member col_span="1" name="id" displayName="Id"/>
</members>
</list_view>
</class>
</UI-defination>
和规则
<UI-defination>
<class name="Role">
<list_view multiselect="true">
<members>
<member name="displayName" sequence="2"/>
<member name="code" sequence="4"/>
</members>
<exclude>
<members>
<member name="id"/>
<member name="creator"/>
</members>
</exclude>
</list_view>
</class>
</UI-defination>
我得到了结果
<member col_span="1" name="creationTS" displayName="CreationTS"/>
<member col_span="1" name="displayName" displayName="DisplayName"/>
<member col_span="1" name="emailAddress" displayName="EmailAddress"/>
<member col_span="1" name="code" displayName="Code"/>
这是我发布的XSLT采用的迈克尔发布的XML输入:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs mf"
xmlns:mf="http://example.com/mf">
<!--
<xsl:param name="rules-uri" select="'test2014062704.xml'"/>
<xsl:variable name="rules-doc" select="doc($rules-uri)"/>
-->
<xsl:variable name="main-input" select="/"/>
<xsl:output indent="yes"/>
<xsl:key name="member" match="members/member" use="@id"/>
<xsl:key name="pos" match="members/member" use="xs:integer(@place)"/>
<xsl:variable name="process" select="members/member"/>
<xsl:variable name="no-key" select="members/member[not(@place)]"/>
<xsl:function name="mf:fill" as="element(member)*">
<xsl:param name="pos" as="xs:integer"/>
<xsl:param name="length" as="xs:integer"/>
<xsl:param name="no-key" as="element(member)*"/>
<xsl:sequence select="if ($pos gt $length)
then ()
else
(if (key('pos', $pos, $main-input))
then (key('pos', $pos, $main-input),
mf:fill($pos + 1, $length, $no-key))
else ($no-key[1], mf:fill($pos + 1, $length, $no-key[position() gt 1])))"/>
</xsl:function>
<xsl:template match="/">
<xsl:sequence select="mf:fill(1, count($process), $no-key)"/>
</xsl:template>
</xsl:stylesheet>
然后在输入上使用Saxon 9.5
<members>
<member id="1" place="9"/>
<member id="2" place="2"/>
<member id="3" place="5"/>
<member id="4"/>
<member id="5"/>
<member id="6"/>
<member id="7"/>
<member id="8"/>
<member id="9"/>
<member id="10"/>
<member id="11"/>
<member id="12"/>
</members>
我得到了结果
<member id="4"/>
<member id="2" place="2"/>
<member id="5"/>
<member id="6"/>
<member id="3" place="5"/>
<member id="7"/>
<member id="8"/>
<member id="9"/>
<member id="1" place="9"/>
<member id="10"/>
<member id="11"/>
<member id="12"/>
与Michael的XSLT 1.0代码生成的顺序相同。
答案 2 :(得分:1)
与@Martin Honnen的回答一样,我的回答也适用于XSLT 1.0(不管它的价值):
<?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" version="1.0" encoding="UTF-8" indent="yes" />
<xsl:variable name="excludes" select="document('Rules.xml')//exclude/members"/>
<xsl:variable name="sequences" select="document('Rules.xml')//list_view/members"/>
<xsl:template match="/">
<members>
<!-- output all member with an explicit sequence -->
<xsl:for-each select="//member">
<xsl:sort select="$sequences/member[@name=current()/@name]/@sequence"/>
<xsl:if test="$sequences/member[@name=current()/@name]/@sequence and not($excludes/member[@name=current()/@name])">
<member><xsl:value-of select="@name"/></member>
</xsl:if>
</xsl:for-each>
<!-- output all member without an explicit sequence -->
<xsl:for-each select="//member">
<xsl:if test="not($sequences/member[@name=current()/@name]/@sequence) and not($excludes/member[@name=current()/@name])">
<member><xsl:value-of select="@name"/></member>
</xsl:if>
</xsl:for-each>
</members>
</xsl:template>
</xsl:stylesheet>
产生结果
<?xml version="1.0" encoding="UTF-8"?>
<members>
<member>displayName</member>
<member>code</member>
<member>creationTS</member>
<member>emailAddress</member>
</members>