Re: [xsl] Finding paths in Visio XML exports - recursion question

Subject: Re: [xsl] Finding paths in Visio XML exports - recursion question
From: Steven Davies <xsl-list@xxxxxxxxxxx>
Date: Sun, 28 Sep 2008 15:00:48 +0100
G. Ken Holman wrote:
At 2008-09-27 20:20 +0100, Steven Davies wrote:
Now, I can use an XPath expression to find the first node in the
document easily enough (it has a certain property in its data set to
"1") and the only way I've been able to find all connected shapes from
this one is to use 3 for-each loops: the first over all <Connect>s
beginning at the shape itself, the second nested loop over all other
endpoints of the <Connect> (there will only ever be one) and the third
over all <Shape>s connected to the <Connect>:

 <xsl:variable name="thisShapeID" select="./@ID"/>
 <xsl:for-each select="../../v:Connects/v:Connect[@ToSheet=$thisShapeID
and @FromCell='BeginX']">
   <xsl:variable name="connectFromSheet" select="./@FromSheet"/>
   <xsl:for-each select="../v:Connect[@FromSheet=$connectFromSheet and
     <xsl:variable name="nextShapeID" select="./@ToSheet"/>
     <xsl:for-each select="../../v:Shapes/v:Shape[@ID=$nextShapeID]">

I had to use the xsl:variables because I couldn't get the equation
[@ID=./@ToSheet], for example, to work (it never matched, any ideas with this?).

Note that "./" as the first step of a location path doesn't do anything ... so where you have (for example) select="./@FromSheet" you need only have select="@FromSheet".

That is also why "[@ID=./@ToSheet]" is equivalent to "[@ID=@ToSheet]" which is why it isn't working for you.

You want "[@ID=current()/@ToSheet]" because in XSLT current() returns what the current node was when you started the XPath address. The current() function is not part of XPath but can be used with XPath in XSLT.

Thanks, that really helped. Now I have the following XPath in one loop instead of the three for-each loops:

<xsl:for-each select="../v:Shape[@ID=../../v:Connects/v:Connect[@FromSheet=../v:Connect[@ToSheet=current()/@ID and @FromCell='BeginX']/@FromSheet and @FromCell='EndX']/@ToSheet]">

This basically does the same as the three loops but in one statement - however, it now takes a very long time to run - over a minute as opposed to about a second. This isn't a major issue as it won't be run very frequently but do you know why this performance hit might have happened?

Inside the innermost xsl:for-each I recursively call the template which
works very well for a straight flow in Visio. However, there can be
infinite loops in the flow so I have to first test whether the <Shape>
has already been output before recursing. This works.

Also the flows can branch off in multiple directions and each branch
needs to be output one at a time (i.e. the nodes before the branch only
need to be output once). This also works.

My problem is that I need to output a message (well, an element - eventually this will be XSL-FO) every time the end of a path is reached. This could be because the flow looped back, that is, the recursion is stopped, or it could be because the end of a branch (and therefore outermost for-each) was reached. While this is relatively easy to do, I end up getting multiple copies of the node output because of the multiple levels of recursion.

If you've stopped when your recursion loops back, how is it you are getting multiple levels of recursion?

Sorry, I'm not too brilliant at explaining things..I mean that for every new connected shape the template is called recursively so that when it gets to the end of a branch the template 'un-recurses' however many times there are objects in the branch.

Does anyone have an idea how to get around this?

A functioning mocked-up data example would help so that you could illustrate what is working and what isn't working. For myself I'm having problems understanding the prose description.

Yes, I thought that might happen! I've created a sample Visio document and uploaded it along with a PDF of what it looks like:

The XSL file I'm using is at:

It seems to work now but if anybody knows why there's such a performance penalty for using the XPath above I'd be very grateful to hear why!

Thanks again,

Current Thread