[quoted text, click to view] "Steve" <steve@nospam.com> wrote in message news:C7CB30CD-E939-4F25-8F24-2D0F9F2B361B@microsoft.com...
> Is there any way of specifying the startMode when using the xslTransform class?
The XslTransform class doesn't afford a direct means of setting a
so-called "start mode" that I'm aware of. Start mode is just an
MSXML-specific means of having multiple 'root' template rules each
with a different mode attribute and choosing one of them to apply.
[quoted text, click to view] > Know that we could use global params, but would rather not have to update
> all the stylesheets and any code that uses msxml and the same stylesheets.
Parameters would make your stylesheets more portable in the long
run, because "start mode" is an implementation-specific feature that
you may not be able to take with you when migrating to another XSLT
processor.
However, I think you can accomplish the same effect by using an
<xsl:import> in a "wrapper" stylesheet. The <xsl:apply-templates>
in the wrapper could select the 'root' template rule in the imported
stylesheet having your desired start mode.
Of course, this <xsl:apply-templates> would appear in the 'root' template
rule of the wrapper stylesheet, thus superceding any 'root' template that
doesn't have a mode attribute in the imported stylesheet. Therefore, you
only want to create this wrapper when you're actually going to specify a
start mode (if no start mode is specified, or start mode is null or the empty
string, then the imported stylesheet is simply used directly; which is exactly
as it would be for the start mode property in MSXML).
Here's a concrete example of an XslTransform-aggregating class that I've
dubbed StartModeTransform exposing a StartMode property and managing
when to use, or not to use, the "wrap and import" stylesheet design.
- - - StartModeTransform.cs
using System;
using System.IO;
using System.Security.Policy;
using System.Text;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Xsl;
/// <summary>
/// Encapsulates an <b>XslTransform</b> and adds <i>start mode</i> capability
/// by "wrapping and importing" the loaded stylesheet as required.
/// </summary>
public class StartModeTransform
{
private XslTransform transformer;
private string startMode;
private bool isAdjusted;
private string baseUrl;
public StartModeTransform( ) : this( new XslTransform( ))
{
;
}
public StartModeTransform( XslTransform xslt)
{
this.transformer = xslt;
}
public string StartMode
{
get
{
return this.startMode;
}
set
{
if ( value != this.startMode )
{
this.startMode = value;
this.isAdjusted = false;
if ( ( ( value == null ) || ( 0 == value.Length ) ) && isAdjusted )
// Un-adjust when StartMode is reset to none.
Load( this.baseUrl);
else
// Re-adjust when StartMode changes.
AdjustForStartMode( );
}
}
}
public virtual void Load( string url)
{
this.baseUrl = url;
this.transformer.Load( url);
}
// Implementation of other Load( ) methods left as an
// exercise for the reader.
public virtual void Transform( IXPathNavigable input, XsltArgumentList args,
TextWriter output, XmlResolver resolver)
{
this.transformer.Transform( input, args, output, resolver);
}
// Implementation of other Transform( ) methods left as
// an exercise for the reader.
protected virtual void AdjustForStartMode( )
{
if ( this.isAdjusted || ( null == this.startMode ) || ( 0 == this.startMode.Length ) )
return;
// Import current XSLT stylesheet inside of wrapper that
// honors StartMode.
XmlDocument adjustedXsl = new XmlDocument();
adjustedXsl.Load( "startMode.xsl");
// Replace two placeholders, one for the xsl:import href
// that points to the wrapped stylesheet.
XmlAttribute hrefAttr = ((XmlElement)(adjustedXsl.DocumentElement.FirstChild)).Attributes[ "href"];
hrefAttr.Value = String.Format( "{0}", this.baseUrl); // use Format to allow for http:// URLs
// The other placeholder specifies the xsl:apply-templates mode
// that is the start mode to be called in the wrapped stylesheet.
XmlAttribute modeAttr = ((XmlElement)(adjustedXsl.DocumentElement.ChildNodes[ 1].FirstChild)).Attributes[ "mode"];
modeAttr.Value = this.startMode;
// Depending on where you keep the XSLT stylesheet being
// loaded, you may need to subclass XmlResolver and specify
// it here (instead of resolver).
XmlUrlResolver resolver = new XmlUrlResolver( );
Evidence evidence = XmlSecureResolver.CreateEvidenceForUrl( this.baseUrl);
this.transformer.Load( adjustedXsl.CreateNavigator(), resolver, evidence);
this.isAdjusted = true;
return;
}
}
- - -
This class depends on a placeholder XSLT stylesheet into which it adjusts the
<xsl:import>'s href attribute, and the <xsl:apply-templates>'s mode attribute,
to affect the "wrapping and importing" of your stylesheet when a StartMode is
assigned.
- - - startMode.xsl
<xsl:stylesheet xmlns:xsl="
http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:import href="X" />
<xsl:template match="/">
<xsl:apply-templates select="/" mode="X" />
</xsl:template>
</xsl:stylesheet>
- - -
The attribute values of this wrapper stylesheet import the originally loaded style-
sheet, and assign the StartMode used to apply the 'root' template of the imported
stylesheet.
Another advantage to using <xsl:import> is that it must appear as the first
child under the <xsl:stylesheet>, and therefore it honors any existing global
parameters in the stylesheets you're loading, and any namespace declarations
in the <xsl:stylesheet> that's imported are respected.
In conclusion, you can't expect every XSLT processor to directly support a
StartMode, but it is still something that can be simulated and overcome
through the skillful application of XSLT.
Derek Harmon