473,233 Members | 1,430 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,233 software developers and data experts.

WriteXml to include xslt reference statement - how?

Hi,

I'm new to using xml/xslt and although I can create an xml document
using the dataset.WriteXml statement, and I have created an xslt to
transform the xml into the output I want, I have to manually add the
xsl reference statement to the xml file.

i.e.
<?xml version="1.0" standalone="yes"?>
<?xml:stylesheet type="text/xsl" href="Questions.xsl"?> --> I have to
add this
<NewDataSet>
<Questions>
<ID>1</ID>
Nov 12 '05 #1
3 4805
"Gordon Moore" <go***********@operamail.com> wrote in message news:eb**************************@posting.google.c om...
I'm new to using xml/xslt and although I can create an xml document
using the dataset.WriteXml statement, and I have created an xslt to
transform the xml into the output I want, I have to manually add the : : <?xml:stylesheet type="text/xsl" href="Questions.xsl"?>


I think the processing instruction you're meaning to write is xml-stylesheet
(with a dash, not xml:stylesheet with a colon), per the recommendation
described here,

http://www.w3.org/TR/xml-stylesheet/

Back to answering your original question, yes, it is possible to get WriteXml( )
to emit this processing instruction automatically. The design necessary involves
intercepting calls to the XmlWriter (or TextWriter, or Stream) and injecting the
processing instruction immediately after the XML declaration (alternately, before
the document element). This interception technique is applicable to any of the
TextWriter or a Stream overloads for WriteXml( ), but to keep this all in the
XML family, let's use the XmlWriter overload, OK? :-)

At first, I wasn't sure which overload of WriteXml( ) you were using since you
were getting an XML declaration with a standalone attribute. I've since learned
that WriteXml( ) has a quirk in it, and I now think I know which overload you're
using. Needless to say, I'll demonstrate how to easily overcome this quirk, so
you can use the XmlWriter solution as well.

First, let's create an XmlTextWriter subclass that you can include in your project.
It's a relatively simple matter to wrap a TextWriter around a FileStream using the
string filename I think you were using in the call to WriteXml( ). I'll explain how
this all works together momentarily, but here's the code:

- - - MagnumWriter.cs
using System;
using System.IO;
using System.Xml;

/// <summary>
/// Magnum Writer injects an xml-stylesheet processing instruction (PI) into the
/// XML serialization from any method that accepts an XmlWriter argument.
/// </summary>
public class MagnumWriter : XmlTextWriter
{
private string xslStylesheetFilename;
private bool xmlDeclWritten;

public MagnumWriter( TextWriter writer, string stylesheetFilename) : base( writer)
{
xslStylesheetFilename = stylesheetFilename;
xmlDeclWritten = false;
}

public override void WriteStartDocument( bool standalone)
{
xmlDeclWritten = true;
base.WriteStartDocument( standalone);
base.WriteProcessingInstruction( "xml-stylesheet", String.Format( "type=\"text/xsl\" href=\"{0}\"",
xslStylesheetFilename) );
}

public override void WriteStartElement( string prefix, string localName, string nsUri)
{
if ( !xmlDeclWritten )
this.WriteStartDocument( true);
base.WriteStartElement( prefix, localName, nsUri);
}
}
- - -

The constructor creates a MagnumWriter, which is really just an XmlTextWriter that
I've overriden a few methods on. In order to create an XmlTextWriter that will send
XML content someplace, I need my constructor to at least support a parameter that
the XmlTextWriter's constructor can accept. In this case, that's the writer argument,
which gets passed to my base( ) (MyBase( writer) for those following along in VB.NET)
and does all the initializations underneath in the XmlTextWriter base class I've derived
from. Additionally, since MagnumWriter is "adding value," it needs to accept the
file name or URL you want to have appear in the href pseudo attribute, so that's the
second argument to it's constructor which gets saved into the xslStylesheetFilename
field for when I write the processing instruction later.

Next is WriteStartDocument( ). Normally when there are a number of overloads and
you're asking yourself which one should you override to get the most bang-for-the-buck,
the answer will be the overload with the most parameters. WriteStartDocument( ) would
just call the more specific WriteStartDocument( bool) anyway, so I only have to override
it once and not override both of them.

WriteStartDocument( ) is normally the place you want to be in most XmlWriter applications
that need supplementary processing instructions added up in the document's prolog, although
processing instructions may also appear anyplace within the document as well (they aren't
restricted to preceding the start element, although in xml-stylesheet's case it does).

As I've implemented WriteStartDocument( ), first I call the base class' WriteStartDocument( )
so it can go ahead with writing the XML declaration, and then I call the WriteProcessing-
Instruction( ) to immediately succeed it with our xml-stylesheet PI.

This might ordinarily be enough, but there's a quirk in some of the WriteXml( ) methods of
DataSet by which they won't necessarily call WriteStartDocument( ). It only writes out the
XML declaration (calling WriteStartDocument( )) when it knows it's writing out an entire
document: start, middle and end. This is the case with the WriteXml( ) overload taking a
string filename, but is not presumed with many of the other overloads. This is probably to
support writing multiple data sets out within the context of a larger containing document
element -- but for this solution it's a quirk that I'll show you how to overcome.

The solution is where the xmlDeclWritten field comes into the picture. Whenever a call
is made to WriteStartDocument( ), this flag is raised and remains raised for the duration.
If the DataSet::WriteXml( ) instead calls WriteStartElement( ) first, instead of WriteStart-
Document( ), meaning that we're going ahead without an XML declaration, then what
I've implemented for WriteStartElement( ) checks the xmlDeclWritten flag to see if it
hasn't been raised yet, and if it hasn't I call WriteStartDocument( ) to raise it (and thereby
inject an XML declaration and the xml-stylesheet PI into the stream).

WriteStartElement( ) then does what any good intercepter method should do, it calls
it's base method implementation as if it weren't even there.

I know any client that produces XML through an XmlWriter will use either WriteStart-
Document( ) or WriteStartElement( ) first, so this ensures that whichever path the code
takes you have an XML declaration and PI emitted when you pipe it through Magnum-
Writer.

- - - InjectingProcInstDemo.cs (except)
using System;
using System.Data;
using System.IO;
using System.Xml;

// . . .

TextWriter streamToFile = new StreamWriter( xmlFilename);
MagnumWriter magnumPI = new MagnumWriter( streamToFile, "Questions.xsl");
magnumPI.Formatting = Formatting.Indented; // optionally set indented formatting of output here..
dataSet1.WriteXml( magnumPI);
magnumPI.Flush( );
magnumPI.Close( ); // close underlying file stream, forgetting this may leave exclusive locks on the file..

// . . .
- - -

This final piece of code demonstrates, for completeness, how you can use a TextWriter
instead of a file name, so that you can call the overload of WriteXml( ) on your DataSet
that accepts XmlWriter-subclasses like the MagnumWriter.
Derek Harmon
Nov 12 '05 #2
Derek - you are a star.

Thank you very much for your informative response. The code works a
treat.

It is really wonderful when people like yourself take so much time and
effort to respond in such a complete way to queries - thanks again.

Thanks for the correction on the correct syntax on xml-stylesheet. I
picked up the ":" version from an online tutorial!

Regards

Gordon

"Derek Harmon" <lo*******@msn.com> wrote in message news:<un*************@TK2MSFTNGP12.phx.gbl>...
"Gordon Moore" <go***********@operamail.com> wrote in message news:eb**************************@posting.google.c om...
I'm new to using xml/xslt and although I can create an xml document
using the dataset.WriteXml statement, and I have created an xslt to
transform the xml into the output I want, I have to manually add the

: :
<?xml:stylesheet type="text/xsl" href="Questions.xsl"?>


I think the processing instruction you're meaning to write is xml-stylesheet
(with a dash, not xml:stylesheet with a colon), per the recommendation
described here,

http://www.w3.org/TR/xml-stylesheet/

Back to answering your original question, yes, it is possible to get WriteXml( )
to emit this processing instruction automatically. The design necessary involves
intercepting calls to the XmlWriter (or TextWriter, or Stream) and injecting the
processing instruction immediately after the XML declaration (alternately, before
the document element). This interception technique is applicable to any of the
TextWriter or a Stream overloads for WriteXml( ), but to keep this all in the
XML family, let's use the XmlWriter overload, OK? :-)

At first, I wasn't sure which overload of WriteXml( ) you were using since you
were getting an XML declaration with a standalone attribute. I've since learned
that WriteXml( ) has a quirk in it, and I now think I know which overload you're
using. Needless to say, I'll demonstrate how to easily overcome this quirk, so
you can use the XmlWriter solution as well.

First, let's create an XmlTextWriter subclass that you can include in your project.
It's a relatively simple matter to wrap a TextWriter around a FileStream using the
string filename I think you were using in the call to WriteXml( ). I'll explain how
this all works together momentarily, but here's the code:

- - - MagnumWriter.cs
using System;
using System.IO;
using System.Xml;

/// <summary>
/// Magnum Writer injects an xml-stylesheet processing instruction (PI) into the
/// XML serialization from any method that accepts an XmlWriter argument.
/// </summary>
public class MagnumWriter : XmlTextWriter
{
private string xslStylesheetFilename;
private bool xmlDeclWritten;

public MagnumWriter( TextWriter writer, string stylesheetFilename) : base( writer)
{
xslStylesheetFilename = stylesheetFilename;
xmlDeclWritten = false;
}

public override void WriteStartDocument( bool standalone)
{
xmlDeclWritten = true;
base.WriteStartDocument( standalone);
base.WriteProcessingInstruction( "xml-stylesheet", String.Format( "type=\"text/xsl\" href=\"{0}\"",
xslStylesheetFilename) );
}

public override void WriteStartElement( string prefix, string localName, string nsUri)
{
if ( !xmlDeclWritten )
this.WriteStartDocument( true);
base.WriteStartElement( prefix, localName, nsUri);
}
}
- - -

The constructor creates a MagnumWriter, which is really just an XmlTextWriter that
I've overriden a few methods on. In order to create an XmlTextWriter that will send
XML content someplace, I need my constructor to at least support a parameter that
the XmlTextWriter's constructor can accept. In this case, that's the writer argument,
which gets passed to my base( ) (MyBase( writer) for those following along in VB.NET)
and does all the initializations underneath in the XmlTextWriter base class I've derived
from. Additionally, since MagnumWriter is "adding value," it needs to accept the
file name or URL you want to have appear in the href pseudo attribute, so that's the
second argument to it's constructor which gets saved into the xslStylesheetFilename
field for when I write the processing instruction later.

Next is WriteStartDocument( ). Normally when there are a number of overloads and
you're asking yourself which one should you override to get the most bang-for-the-buck,
the answer will be the overload with the most parameters. WriteStartDocument( ) would
just call the more specific WriteStartDocument( bool) anyway, so I only have to override
it once and not override both of them.

WriteStartDocument( ) is normally the place you want to be in most XmlWriter applications
that need supplementary processing instructions added up in the document's prolog, although
processing instructions may also appear anyplace within the document as well (they aren't
restricted to preceding the start element, although in xml-stylesheet's case it does).

As I've implemented WriteStartDocument( ), first I call the base class' WriteStartDocument( )
so it can go ahead with writing the XML declaration, and then I call the WriteProcessing-
Instruction( ) to immediately succeed it with our xml-stylesheet PI.

This might ordinarily be enough, but there's a quirk in some of the WriteXml( ) methods of
DataSet by which they won't necessarily call WriteStartDocument( ). It only writes out the
XML declaration (calling WriteStartDocument( )) when it knows it's writing out an entire
document: start, middle and end. This is the case with the WriteXml( ) overload taking a
string filename, but is not presumed with many of the other overloads. This is probably to
support writing multiple data sets out within the context of a larger containing document
element -- but for this solution it's a quirk that I'll show you how to overcome.

The solution is where the xmlDeclWritten field comes into the picture. Whenever a call
is made to WriteStartDocument( ), this flag is raised and remains raised for the duration.
If the DataSet::WriteXml( ) instead calls WriteStartElement( ) first, instead of WriteStart-
Document( ), meaning that we're going ahead without an XML declaration, then what
I've implemented for WriteStartElement( ) checks the xmlDeclWritten flag to see if it
hasn't been raised yet, and if it hasn't I call WriteStartDocument( ) to raise it (and thereby
inject an XML declaration and the xml-stylesheet PI into the stream).

WriteStartElement( ) then does what any good intercepter method should do, it calls
it's base method implementation as if it weren't even there.

I know any client that produces XML through an XmlWriter will use either WriteStart-
Document( ) or WriteStartElement( ) first, so this ensures that whichever path the code
takes you have an XML declaration and PI emitted when you pipe it through Magnum-
Writer.

- - - InjectingProcInstDemo.cs (except)
using System;
using System.Data;
using System.IO;
using System.Xml;

// . . .

TextWriter streamToFile = new StreamWriter( xmlFilename);
MagnumWriter magnumPI = new MagnumWriter( streamToFile, "Questions.xsl");
magnumPI.Formatting = Formatting.Indented; // optionally set indented formatting of output here..
dataSet1.WriteXml( magnumPI);
magnumPI.Flush( );
magnumPI.Close( ); // close underlying file stream, forgetting this may leave exclusive locks on the file..

// . . .
- - -

This final piece of code demonstrates, for completeness, how you can use a TextWriter
instead of a file name, so that you can call the overload of WriteXml( ) on your DataSet
that accepts XmlWriter-subclasses like the MagnumWriter.
Derek Harmon

Nov 12 '05 #3
Ahhh, the syntax error was mine after all. Clearly I can't read...

Gordon
go***********@operamail.com (Gordon Moore) wrote in message news:<eb**************************@posting.google. com>...
Derek - you are a star.

Thank you very much for your informative response. The code works a
treat.

It is really wonderful when people like yourself take so much time and
effort to respond in such a complete way to queries - thanks again.

Thanks for the correction on the correct syntax on xml-stylesheet. I
picked up the ":" version from an online tutorial!

Regards

Gordon

"Derek Harmon" <lo*******@msn.com> wrote in message news:<un*************@TK2MSFTNGP12.phx.gbl>...
"Gordon Moore" <go***********@operamail.com> wrote in message news:eb**************************@posting.google.c om...
I'm new to using xml/xslt and although I can create an xml document
using the dataset.WriteXml statement, and I have created an xslt to
transform the xml into the output I want, I have to manually add the

: :
<?xml:stylesheet type="text/xsl" href="Questions.xsl"?>


I think the processing instruction you're meaning to write is xml-stylesheet
(with a dash, not xml:stylesheet with a colon), per the recommendation
described here,

http://www.w3.org/TR/xml-stylesheet/

Back to answering your original question, yes, it is possible to get WriteXml( )
to emit this processing instruction automatically. The design necessary involves
intercepting calls to the XmlWriter (or TextWriter, or Stream) and injecting the
processing instruction immediately after the XML declaration (alternately, before
the document element). This interception technique is applicable to any of the
TextWriter or a Stream overloads for WriteXml( ), but to keep this all in the
XML family, let's use the XmlWriter overload, OK? :-)

At first, I wasn't sure which overload of WriteXml( ) you were using since you
were getting an XML declaration with a standalone attribute. I've since learned
that WriteXml( ) has a quirk in it, and I now think I know which overload you're
using. Needless to say, I'll demonstrate how to easily overcome this quirk, so
you can use the XmlWriter solution as well.

First, let's create an XmlTextWriter subclass that you can include in your project.
It's a relatively simple matter to wrap a TextWriter around a FileStream using the
string filename I think you were using in the call to WriteXml( ). I'll explain how
this all works together momentarily, but here's the code:

- - - MagnumWriter.cs
using System;
using System.IO;
using System.Xml;

/// <summary>
/// Magnum Writer injects an xml-stylesheet processing instruction (PI) into the
/// XML serialization from any method that accepts an XmlWriter argument.
/// </summary>
public class MagnumWriter : XmlTextWriter
{
private string xslStylesheetFilename;
private bool xmlDeclWritten;

public MagnumWriter( TextWriter writer, string stylesheetFilename) : base( writer)
{
xslStylesheetFilename = stylesheetFilename;
xmlDeclWritten = false;
}

public override void WriteStartDocument( bool standalone)
{
xmlDeclWritten = true;
base.WriteStartDocument( standalone);
base.WriteProcessingInstruction( "xml-stylesheet", String.Format( "type=\"text/xsl\" href=\"{0}\"",
xslStylesheetFilename) );
}

public override void WriteStartElement( string prefix, string localName, string nsUri)
{
if ( !xmlDeclWritten )
this.WriteStartDocument( true);
base.WriteStartElement( prefix, localName, nsUri);
}
}
- - -

The constructor creates a MagnumWriter, which is really just an XmlTextWriter that
I've overriden a few methods on. In order to create an XmlTextWriter that will send
XML content someplace, I need my constructor to at least support a parameter that
the XmlTextWriter's constructor can accept. In this case, that's the writer argument,
which gets passed to my base( ) (MyBase( writer) for those following along in VB.NET)
and does all the initializations underneath in the XmlTextWriter base class I've derived
from. Additionally, since MagnumWriter is "adding value," it needs to accept the
file name or URL you want to have appear in the href pseudo attribute, so that's the
second argument to it's constructor which gets saved into the xslStylesheetFilename
field for when I write the processing instruction later.

Next is WriteStartDocument( ). Normally when there are a number of overloads and
you're asking yourself which one should you override to get the most bang-for-the-buck,
the answer will be the overload with the most parameters. WriteStartDocument( ) would
just call the more specific WriteStartDocument( bool) anyway, so I only have to override
it once and not override both of them.

WriteStartDocument( ) is normally the place you want to be in most XmlWriter applications
that need supplementary processing instructions added up in the document's prolog, although
processing instructions may also appear anyplace within the document as well (they aren't
restricted to preceding the start element, although in xml-stylesheet's case it does).

As I've implemented WriteStartDocument( ), first I call the base class' WriteStartDocument( )
so it can go ahead with writing the XML declaration, and then I call the WriteProcessing-
Instruction( ) to immediately succeed it with our xml-stylesheet PI.

This might ordinarily be enough, but there's a quirk in some of the WriteXml( ) methods of
DataSet by which they won't necessarily call WriteStartDocument( ). It only writes out the
XML declaration (calling WriteStartDocument( )) when it knows it's writing out an entire
document: start, middle and end. This is the case with the WriteXml( ) overload taking a
string filename, but is not presumed with many of the other overloads. This is probably to
support writing multiple data sets out within the context of a larger containing document
element -- but for this solution it's a quirk that I'll show you how to overcome.

The solution is where the xmlDeclWritten field comes into the picture. Whenever a call
is made to WriteStartDocument( ), this flag is raised and remains raised for the duration.
If the DataSet::WriteXml( ) instead calls WriteStartElement( ) first, instead of WriteStart-
Document( ), meaning that we're going ahead without an XML declaration, then what
I've implemented for WriteStartElement( ) checks the xmlDeclWritten flag to see if it
hasn't been raised yet, and if it hasn't I call WriteStartDocument( ) to raise it (and thereby
inject an XML declaration and the xml-stylesheet PI into the stream).

WriteStartElement( ) then does what any good intercepter method should do, it calls
it's base method implementation as if it weren't even there.

I know any client that produces XML through an XmlWriter will use either WriteStart-
Document( ) or WriteStartElement( ) first, so this ensures that whichever path the code
takes you have an XML declaration and PI emitted when you pipe it through Magnum-
Writer.

- - - InjectingProcInstDemo.cs (except)
using System;
using System.Data;
using System.IO;
using System.Xml;

// . . .

TextWriter streamToFile = new StreamWriter( xmlFilename);
MagnumWriter magnumPI = new MagnumWriter( streamToFile, "Questions.xsl");
magnumPI.Formatting = Formatting.Indented; // optionally set indented formatting of output here..
dataSet1.WriteXml( magnumPI);
magnumPI.Flush( );
magnumPI.Close( ); // close underlying file stream, forgetting this may leave exclusive locks on the file..

// . . .
- - -

This final piece of code demonstrates, for completeness, how you can use a TextWriter
instead of a file name, so that you can call the overload of WriteXml( ) on your DataSet
that accepts XmlWriter-subclasses like the MagnumWriter.
Derek Harmon

Nov 12 '05 #4

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

7
by: Adi Schwarz | last post by:
I was asking myself what solution is better considering performance. I want to create some classes depending on a varable (for different languages). Of course, if the classes are huge I write...
5
by: Brett conklin | last post by:
I would like to not use the google groups as a crutch in my XSLT journey. What is the best xslt reference out there? Is it a book? Is it a web site? I am finding that I can come up with nearly...
2
by: Jon Shemitz | last post by:
Once, I happened on a fairly complete set of xsl: language element docs in VS.2003. I can't find it again - can anyone tell me how to navigate to it from either the Contents or the Index? -- ...
3
by: Peter Row | last post by:
Hi, I have 2 XML files and 1 XSLT file. The second XML file has the following declarative 1st line: <?xml version="1.0" encoding="UTF-8" standalone="yes"?> ....the 1st one (the one to be...
4
by: Lord0 | last post by:
Hi there, Is the following possible with XSLT? Given the following example XML docs: <!-- doc 1--> <user> <username>myUsername</username> <password></password> <phone>12345</phone>
6
by: Puzzled | last post by:
http://www.biglist.com/lists/xsl-list/archives/200303/msg01242.html purports to show how xslt can be used to copy all of an xhtml file & selectively transform certain nodes. The copy works fine on...
0
by: Vince Filby | last post by:
Should WriteXml include the tags that encompass the object? Take a Phone class for example, should WriteXml() emit this: <Phone> <Description>text</Description> <Number>1-222-333-1234</Number>...
2
jkmyoung
by: jkmyoung | last post by:
Here's a short list of useful xslt general tricks that aren't taught at w3schools. Attribute Value Template Official W3C explanation and example This is when you want to put dynamic values...
3
by: Simon Brooke | last post by:
I'm trying to do internationalisation by using xsl:include to include a different file depending on the locale setting, and I'm completely failing. I've tried several different approaches: ...
3
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 3 Jan 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). For other local times, please check World Time Buddy In...
2
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 7 Feb 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:30 (7.30PM). In this month's session, the creator of the excellent VBE...
0
by: stefan129 | last post by:
Hey forum members, I'm exploring options for SSL certificates for multiple domains. Has anyone had experience with multi-domain SSL certificates? Any recommendations on reliable providers or specific...
0
Git
by: egorbl4 | last post by:
Скачал я git, хотел начать настройку, а там вылезло вот это Что это? Что мне с этим делать? ...
0
by: DolphinDB | last post by:
The formulas of 101 quantitative trading alphas used by WorldQuant were presented in the paper 101 Formulaic Alphas. However, some formulas are complex, leading to challenges in calculation. Take...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: Aftab Ahmad | last post by:
Hello Experts! I have written a code in MS Access for a cmd called "WhatsApp Message" to open WhatsApp using that very code but the problem is that it gives a popup message everytime I clicked on...
0
by: Aftab Ahmad | last post by:
So, I have written a code for a cmd called "Send WhatsApp Message" to open and send WhatsApp messaage. The code is given below. Dim IE As Object Set IE =...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.