Re: [xsl] Re: The Solution -- Re: how to rearrange nodes based on a dependency graph?

Subject: Re: [xsl] Re: The Solution -- Re: how to rearrange nodes based on a dependency graph?
From: Dimitre Novatchev <dnovatchev@xxxxxxxxx>
Date: Sat, 22 Dec 2001 10:44:49 -0800 (PST)
Hi Gunther,

> Well, instead of wondering about the
> specs, I discovered a related problem with your topological
> sort. As beautiful as it is, it disturbs document order where
> it isn't warranted by the dependencies. For example, let's
> say I have 3 cliques of dependent nodes and no link between
> them. What happens with top sort is that those three cliques
> are all intermingled. The trick is to keep the document sort
> order if it doesn't need to be changed. I may end up to go
> back to my naive check-off list approach (recurse through
> node list and walk the dependencies, always propagating a node
> set of already processed nodes, and checking that a node
> isn't in the done set before processing it. I couldn't make
> this to work only because I refused to use the node-set function.
> Now I am free to do so :-)
> 

Here's another solution, which "keeps the cliques" together.

Let's have the following source xml document:

<document xml:space="preserve">
    <frag id='1'>
        <requires>2</requires>
        <requires>3</requires>
    </frag>

    <frag id='2'>
        <requires>4</requires>
        <requires>5</requires>
    </frag>

    <frag id='3'>
        <requires>5</requires>
    </frag>

    <frag id='4' />

    <frag id='5' />
    
    <frag id='6'>
        <requires>7</requires>
        <requires>8</requires>
    </frag>

    <frag id='7'>
        <requires>9</requires>
    </frag>
    
    <frag id='8'>
        <requires>9</requires>
    </frag>

    <frag id='9'>
        <requires>10</requires>
        <requires>11</requires>
    </frag>

     <frag id='10' />

    <frag id='11' />
   
</document>

This contains "two cliques" which are graphically represented bellow:

       1
      / \
     2   3
    / \ /
   4   5

and

       6
      / \
     7   8
      \ /
       9
      / \
     10 11

The algorithm is once again simple -- for every position on the list starting from
position 1 we move the element at this position right before the first preceding
element, that depends on it. Then we repeat this with the next position but with the
newly formed list, ... etc. until the last position has been treated.

Here's the stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
xmlns:msxsl="urn:schemas-microsoft-com:xslt">
  <xsl:output indent="yes" omit-xml-declaration="yes"/>
  <xsl:template match="/">
    <xsl:call-template name="topSort">
      <xsl:with-param name="pList" select="/*/frag"/>
    </xsl:call-template>
  </xsl:template>
  
  <xsl:template name="topSort">
    <xsl:param name="pList" select="/.."/>
    <xsl:param name="pPositon" select="1"/>
    
    <xsl:choose>
      <xsl:when test="$pPositon > count($pList)">
        <xsl:copy-of select="$pList"/>
      </xsl:when>
      <xsl:otherwise>
	    <xsl:variable name="vThisNode" select="$pList[$pPositon]"/>
	    <xsl:variable name="vfirstPrecedingDependent"
	                  select="$pList[position() &lt; $pPositon
	                               and
	                                 requires = $vThisNode/@id
	                                 ][1]"/>
	    <xsl:variable name="vInsertPosition">
	      <xsl:choose>
	        <xsl:when test="$vfirstPrecedingDependent">
	          <xsl:value-of select="count($vfirstPrecedingDependent
                                                           /preceding-sibling::*)"/>
	        </xsl:when>
	        <xsl:otherwise>-1</xsl:otherwise>
	      </xsl:choose>
	    </xsl:variable> 
	    
	    <xsl:variable name="vrtfNewList">
	      <xsl:choose>
	        <xsl:when test="$vfirstPrecedingDependent">
	   	  <xsl:copy-of select="$pList[position() &lt;= $vInsertPosition]"/>
		  <xsl:copy-of select="$vThisNode"/>
		  <xsl:copy-of select="$pList[position() > $vInsertPosition
				            and
				              position() != $pPositon
				              ]"/>
		</xsl:when>
		<xsl:otherwise/>
	      </xsl:choose>
	    </xsl:variable>
		 
	    <xsl:variable name="vNewList" 
		          select="msxsl:node-set($vrtfNewList)
                                                      /*[$vfirstPrecedingDependent]
		                  | $pList[not($vfirstPrecedingDependent)]"/>
	    <xsl:call-template name="topSort">
	      <xsl:with-param name="pList" select="$vNewList"/>
	      <xsl:with-param name="pPositon" select="$pPositon + 1"/>
	   </xsl:call-template>
       </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

When applied on the above source xml document, this transformation produces the
following result:

<frag id="4" />
<frag id="5" />
<frag id="2">
        <requires>4</requires>
        <requires>5</requires>
</frag>
<frag id="3">
        <requires>5</requires>
</frag>
<frag id="1">
        <requires>2</requires>
        <requires>3</requires>
</frag>
<frag id="10" />
<frag id="11" />
<frag id="9">
       <requires>10</requires>
        <requires>11</requires>
</frag>
<frag id="7">
        <requires>9</requires>
</frag>
<frag id="8">
        <requires>9</requires>
</frag>
<frag id="6">
        <requires>7</requires>
        <requires>8</requires>
</frag>

As you can see, the two components of connectivity are not intermingled now.

Hope this helped.

Cheers,
Dimitre Novatchev.

__________________________________________________
Do You Yahoo!?
Send your FREE holiday greetings online!
http://greetings.yahoo.com

 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread