467,895 Members | 1,391 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 467,895 developers. It's quick & easy.

xsl template startMode in system.xml.xsl.xslTransform

Is there any way of specifying the startMode when using the xslTransform class?

We are updating code which used msxml to the system.xml classes but can find
no way to specify the startMode.
We use this so that we can specify different templates to be used by the
same xml node.

Know that we could use global params, but would rather not have to update
all teh stylesheets and any code that uses msxml and the same stylesheets.

Thanks
Nov 12 '05 #1
  • viewed: 1974
Share:
3 Replies
"Steve" <st***@nospam.com> wrote in message news:C7**********************************@microsof t.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.
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.FirstChi ld)).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.ChildNod es[ 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
Nov 12 '05 #2
Derek,

Thanks for the very detailed info.
agree that "startMode" is msxml specific, but the mode attribute of an xslt
template is part of the xslt standard.
Is there no way to specify the mode to be used when evaluating what template
should be used?

As an example, if we have a stylesheet with some order processing templates:

<xsl:template match="order" mode="buy">
<!-- process here -->
</xsl:template>

<xsl:template match="order" mode="amend">
<!-- process here -->
</xsl:template>

<xsl:template match="order" mode="cancel">
<!-- process here -->
</xsl:template>

in a stylsheet we could specify what template should be called by:
<!-- processing stuff -->
<xsl:choose>
<xsl:when test="conditionA"><xsl:apply-templates select="."
mode="amend"/></xsl:when>
<xsl:when test="conditionB"><xsl:apply-templates select="."
mode="cancel"/></xsl:when>
<xsl:otherwise><xsl:apply-templates select="." mode="buy"/></xsl:otherwise>
</xsl:choose>

What I'd like to be able to do is, within my .NET code, when processing an
order node, get the stylesheet to process the template I want it to by
specifying the mode...?

Otherwise I will use the concrete example you have provided

Thanks very much for your input, very usefull
Steve

"Derek Harmon" wrote:
"Steve" <st***@nospam.com> wrote in message news:C7**********************************@microsof t.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.
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.FirstChi ld)).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.ChildNod es[ 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

Nov 12 '05 #3
Hi Steve,

I don't think mode has been implemented in .net xml. However, I think we
can achieve the same goal with the concrete example Derek has provided.

Kevin Yu
=======
"This posting is provided "AS IS" with no warranties, and confers no
rights."

Nov 12 '05 #4

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

5 posts views Thread by laks | last post: by
3 posts views Thread by Grep J | last post: by
1 post views Thread by Praveen | last post: by
1 post views Thread by lenzdata | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.