Sorting in XSLT from two xml files -
i have these 2 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 following rules
- rules.xml/members/member should excluded list
- element should display according sequence attribute in rules.xml
- those element not present in rules.xml/members/member should display according natural order in default.xml.
expected output is....
creationts
emailaddress
displayname
code
then elements has sequence attr, should @ exact position. void position should filled natural order of remaining element.(i.e. elements don't have sequence attr., default.xml)
imho, not sorting problem, queuing problem.
let simplify example having members of 2 types: placed members, place in queue reserved, , ordinary members need fill gaps between 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 described follows:
the reserved members sorted reserved place.
each reserved member "calls" group of ordinary members seated ahead of it.
in our example, have reserved members @ places 2, 5 , 9. before seating reserved member @ place 9, need call group of 3 ordinary members seated @ places 6, 7 , 8.
the size of group equal size of gap between current member's reserved place , place of preceding reserved sibling. that's 9 - 5 - 1 = 3 in our example.
the starting position of group can deduced follows: since preceding member's reserved place #5, 5 members have been seated; out of these, 2 members (at places #2 , #5) reserved members, therefore 3 ordinary members have been seated , our group starts @ position 5 - 3 + 1 = 4.
the last reserved member calls rest of ordinary members seated after it.
here's 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 gap ordinary members --> <xsl:for-each select="$ordinary-members[$gap-start <= position() , position() < $gap-start + $gap-size]"> <xsl:copy-of select="."/> </xsl:for-each> <!-- output 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 above input example, 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>
Comments
Post a Comment