Re: [xsl] relative path from one node to another

Subject: Re: [xsl] relative path from one node to another
From: Dimitre Novatchev <dnovatchev@xxxxxxxxx>
Date: Fri, 20 May 2005 05:55:44 +1000
I wrote two year ago code that produces the absolute path of a file
given its relative path to the absolute path of another file:

    http://www.stylusstudio.com/xsllist/200501/post21280.html

    http://groups.google.co.uk/group/microsoft.public.xml/browse_frm/thread/6
be70a1352644ff1/def66c8ed30c8c46?hl=en&lr=&ie=UTF-8&oe=UTF-8&rnum=1&prev=/gro
ups%3Fq%3Dnovatchev%2Brelative%2Bpath%26hl%3Den%26lr%3D%26ie%3DUTF-8%26oe%3DU
TF-8%26selm%3Db8ujil%2524dpl9r%25241%2540ID-152440.news.dfncis.de%26rnum%3D1#
def66c8ed30c8c46



Cheers,
Dimitre Novatchev.



On 5/20/05, Richard Lewis <richardlewis@xxxxxxxxxxxxxx> wrote:
> Hi there,
>
> I would have thought that the answer to this would be simple but I can't
> work it out.
>
> I have a document which represents an entire website and contains
> structural 'section' elements and lots of other mixed content.
>
> These 'section' elements all have a unique 'id' field and come in two
> flavors: their 'display' attributes contain either the value 'page',
> meaning that they should be rendered in a separate result document, or
> 'inline', meaning that they should be rendered as part of the content of
> their ancestor 'page' section. Whenever a 'page' section element is
> nested inside another 'page' section element, this relationship is
> reflected in the result documents by a corresponding directory
> structure:
>
> example document:
> <document>
>  <section id="index" display="page">
>    <!-- content -->
>  </section>
>  <section id="staff" display="page">
>    <section id="permanent" display="page">
>      <section id="tom" display="page">
>        <!-- content -->
>      </section>
>      <section id="dick" display="page">
>        <!-- content -->
>      </section>
>      <section id="harry" display="page">
>        <!-- content -->
>      </section>
>    </section>
>    <section id="permanent" display="page">
>      <section id="jim" display="inline">
>        <!-- content -->
>      </section>
>      <section id="jon" display="inline">
>        <!-- content -->
>      </section>
>    </section>
>  </section>
>  <section id="research" display="page">
>    <section id="ai" display="inline">
>      <!-- content -->
>    </section>
>    <section id="algorithms" display="inline">
>      <!-- content -->
>    </section>
>  </section>
> </document>
>
> should produce following result documents set:
> ROOT/
>  +-- staff/
>     +-- permanent/
>         +-- tom.html
>         +-- dick.html
>         +-- harry.html
>     +-- temporary.html
>  +-- index.html
>  +-- research.html
>
> I've written an xsl function which correctly calculates the necessary
> file name to pass to xsl:result-document within the 'section' template
> so the above example works so far.
>
> Also in my document I have a number of 'link' elements which can either
> have an 'href' attribute and link to an external resource or they can
> have a 'section' attribute which is the 'id' value of a 'section'
> element; in this case, the link element should produce an HTML <a> tag
> with an 'href' value of the relative path from the result document in
> which the link element occurs to the result document of the given
> 'section' element.
>
> There doesn't seem to be an XPath function to calculate the relative
> path from one node to another (though even if there were it wouldn't
> solve the problem as I need it to consider only those nodes with name
> 'section' and '@display="page"' as 'path nodes').
>
> I have tried writing a function which takes two 'id' values as arguments
> and calculates the relative result document filesystem path between the
> two nodes which they represent but I haven't had much luck! This is what
> I've got so far:
>
> <xsl:function name="my:relative-path">
>  <xsl:param name="from-id" />
>  <xsl:param name="to-id" />
>
>  <!-- find the descendant 'section' node with @display='page' closest
>  to the 'section' node with @id=$from-id: -->
>  <xsl:variable name="from-node" select="if ($from-id='ROOT') / else
>
//*[@id=$from-id]//ancestor-or-self::section[@display='page'][position()==las
t()]"
>  />
>  <!-- find the descendant 'section' node with @display='page' closest
>  to the 'section' node with @id=$to-id: -->
>  <xsl:variable name="to-node" select="if ($to-id='ROOT') / else
>
//*[@id=$to-id]//ancestor-or-self::section[@display='page'][position()==last(
)]"
>  />
>
>  <!-- find the first common ancestor 'section' node (or root node) -->
>  <xsl:for-each
>  select="$from-node//ancestor-or-self::section[@display='page'] | /">
>    <xsl:variable name="ifrom" select="." />
>    <xsl:for-each
>    select="$to-node//ancestor-or-self::section[@display='page'] | /">
>      <xsl:if test=".=$ifrom"><xsl:variable name="common-ancestor"
>      select="." /></xsl:if>
>    </xsl:for-each>
>  </xsl:for-each>
>
>  <!-- count the number of 'section' nodes from $common-ancestor to
>  $from-node (along the descendant axis)-->
>  <!-- return that many '../' strings -->
>  <!-- HOW? -->
>
>  <!-- for each 'section' node from $to-node to $common-ancestor (along
>  the ancestor axis) -->
>  <!-- return concat(@id, '/') -->
>  <!-- HOW? -->
> </xsl:function>
>
> (I haven't tested this at all yet. I am right in thinking that the
> xsl:function element won't know about the current source tree? And that,
> consequently, I won't be able to use '/' or '//*[@id...' in the first
> two xsl:variable elements?)
>
> As you can see, I don't know how to implement this algorithm.
> Furthermore, I don't even know if this algorithm is best solution to the
> problem!
>
> Any help or ideas would be very much appreciated!
>
> Thanks very much,
> Richard

Current Thread