Re: FW: [xsl] FW: 2-step transformation

Subject: Re: FW: [xsl] FW: 2-step transformation
From: "M. David Peterson" <m.david@xxxxxxxxxx>
Date: Wed, 07 Jul 2004 07:37:36 -0600
I wish I could take credit but just like I told Ranjan I either picked this or a similar solution up off DaveP's( FAQ and recycled it or learned it directly from one of Michael Kay's( or Jeni Tennison's( posts. It may have even been from Wendell Piez( or Dimitre Novatchev( or Steve Muench( or any number of the early pioneers of this list and of XSLT. I came in too late in the game to claim any credit for the solutions I post back to the list so the credit should go to one or several of those folks for sure. But I am more than happy to be a messenger as I'm sure you will be for someone else new to the list a bit later on down the road. It's pretty neat how the whole system works :)

Best regards,

 :: Saxon.NET is available in an early beta release to those willing to help eradicate bugs by
    testing features and performance and reporting back the results with suggestions for improvement ::

 :: Please visit to learn more about this early implementation and how you can help bring
    the bits to code complete and ultimately XSLT 2.0, XPath 2.0, and XQuery support to the .NET 1.1 and 2.0 framework ::

Robert Soesemann wrote:
Your answer was definitely great help. No I can solve it. Thank you very
very much!

-----Original Message-----
From: M. David Peterson [mailto:m.david@xxxxxxxxxx] Sent: Wednesday, July 07, 2004 14:03 PM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: Re: FW: [xsl] FW: 2-step transformation

Robert Soesemann wrote:

But in XSL I have no arrays to iterate over again and again and no global variables.

You dont have arrays, youre right... but you do have something much
better in the elements of your XML file. Show me an array[] that
contains more descriptive and complex information/data than what an XML file can
contain and Ill show you code that wont compile.

The short answer to your problem is to use string-length(); e.g.
<xsl:variable name="length" select="string-length(/items)"/> compare
that to your max-length... if its greater then create another variaable to hold the
value of max-length divided by the count of the elements (e.g.
<xsl:variable name="max-individual-length" select="$max-length div count(/items)"/>.
Then you use this number within a substring() function to cut off each
string when it reaches the maximum value allowed for each string (e.g.
<xsl:value-of select="substring(item, 1, $max-individual-length)"/>)

If you want to get even further detailed you can check to see if
max-individual-length is greater than the length of the current string
and then rewrite this using xsl:apply-templates or xsl:call-templates using the
xsl:with-param to tell the matching template to add a bit more to the maximum-sting-length allowed for the current element to make up the

Hope this helps!



Any ideas how to solve this truncation thing.

Cheers Robert

-----Original Message-----
From: M. David Peterson [mailto:m.david@xxxxxxxxxx]
Sent: Wednesday, July 07, 2004 12:51 PM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: Re: [xsl] FW: 2-step transformation

Hey Robert,

While I wouldnt recommend this particular implementation for anything larger than a "Breadcrumbs" XML source file(unless your mapping the library of congress most breadcrumb files should be somewhat manageable -- im guessing yours is as well) here's what I used on the Saxon.NET project site.
Heres the link to see the actual implementation:

The genearal idea... Create an XML that maps to your site structure that starts with a "links" node as the main parent with all underlying

descendants set to the name "link" and an "href" attribute set to the current directory value (I use a relative reference) and then place the reference to this
file within the document function and place that into a variable



<xsl:variable name="links" select="document('links.xml')"/>

I then use a seperate "index.xml" that resides in each directory with an element that contains the value of the current directory (in the same relative format -- I usually set all of these to the root of the site by using a preceding "/" such as "/x2x2x/home" instead of "x2x2x/home" but thats up to you and beyond the scope of your question

as to which is more appropriate for your situation. This index.xml contains all of the necessary
content data the page for this directory correctly. It is passed to


transformation process as the main data file to be transformed. As


I can just set the following param (used to compare with the href value


each "link" element until a match is found) to the location of that
element like so: (Note: This is the same general idea that you are using the


attribute for although the xml parser will notice the id attribute as


unique identifier where as my method will not... depending on your future


or what else you may use the id attribute for you can decide which is
more appropriate for your particular case)

<xsl:param name="curDir" select="/page/curDir"/>

I chose to reference the above as an xsl:param in case you decide to pass this value as a parameter via whatever implemenation you are using to transform your file. It will work either way but if you choose to implement it the way I did then I would change it to a xsl:variable instead to
ensure a more consistent practice of proper use throughout your



The params from above are passed into this code block which outputs the appropriate bread crumbs and then continues the transforation of the rest of the stylesheet. As you can see, with an embedded xsl:for-each element and a reference to all descendant-or-self "link" elements using "//link" this
is definitely not something you want to use with a large data source


process through :)

<xsl:for-each select="$links/links//link[@href = $curDir]/ancestor-or-self::link">
<xsl:variable name="href">/x2x2x<xsl:for-each select="ancestor-or-self::link">/<xsl:value-of
<a href="{$href}" class="locationA"><xsl:value-of select="@common"/></a> <xsl:if test="position() != last()"> &gt; </xsl:if>
// by the way, the @common attribute value used above is the


or friendly name for the directory
	// using capitalized first letters and spaces between each word


the directory name. Its part of each link element. </xsl:for-each>

And that should do it...

Hope this helps!


:: Got a few spare moments to write some C# code for the future of XSLT on the .NET platform? ::
:: Visit the Saxon.NET project site found at to learn more ::

Robert Soesemann wrote:


what I am trying to do is create a breadcrumb trail based on a current

page id and a sitemap XML document. In my page.xml I have a placeholder

<?xml-stylesheet type="text/xsl"


	<add-breadcrumb pageid="ID5"/>    <--------- final breadcrumb
HTML fragment should go here

Based on its @pageid the first XSL(generate-breadcrumb.xsl) generates this XML fragment:

  		<item url=""area1.xml" label="area1"/>
  		<item url=""area2.xml" label="area2"/>

<item url=""areaN.xml" label="areaN"/>

 	 	<page label="thisPage"/>

To do styling and truncation task based on the page width, I need to send this fragment through a Second XSL (style-breadcrumb.xsl) which generates the actual HTML fragment which then be should placed in the page.xml.

How can I realise this 2-step transformation. Any ideas are welcome.

Best regards,


XSL-List info and archive:
To unsubscribe, go to:
or e-mail: <mailto:xsl-list-unsubscribe@xxxxxxxxxxxxxxxxxxxxxx>

XSL-List info and archive:
To unsubscribe, go to:
or e-mail: <mailto:xsl-list-unsubscribe@xxxxxxxxxxxxxxxxxxxxxx>

--+------------------------------------------------------------------ XSL-List info and archive: To unsubscribe, go to: or e-mail: <mailto:xsl-list-unsubscribe@xxxxxxxxxxxxxxxxxxxxxx> --+--

XSL-List info and archive:
To unsubscribe, go to:
or e-mail: <mailto:xsl-list-unsubscribe@xxxxxxxxxxxxxxxxxxxxxx>

Current Thread