I have these two xmls 1> 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>
I want display list of member element according to following rules
Then the elements which has sequence attr, they should be at that exact position. Then void position should get filled by the natural order of remaining element.(i.e. by the elements which don't have sequence attr., from default.xml)
IMHO, this is not a sorting problem, but a queuing problem.
Let us simplify the example by having members of two types: placed members, whose place in the queue is reserved, and ordinary members that need to fill the gaps between the placed members.
<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>
The queuing algorithm could be described as follows:
The reserved members are sorted by their reserved place.
Each reserved member "calls" a group of ordinary members to be seated ahead of it.
In our example, we have reserved members at places 2, 5 and 9. Before seating the reserved member at place 9, we need to call a group of 3 ordinary members to be seated at places 6, 7 and 8.
The size of this group is equal to the size of the gap between the current member's reserved place and the place of its preceding reserved sibling. That's 9 - 5 - 1 = 3 in our example.
The starting position of this group can be deduced as follows: since the preceding member's reserved place is #5, then 5 members have already been seated; out of these, 2 members (at places #2 and #5) are reserved members, therefore only 3 ordinary members have been seated and our group starts at position 5 - 3 + 1 = 4.
The last reserved member calls the rest of the ordinary members to be seated after it.
Here's an example of implementation in 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>
When applied to the above input example, the result is:
<?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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With