As TechEd and the Saxon.NET Birds of a Feather session quickly approach it seems its time to start pushing hard at both finalization of the bits as well as sample code to help gain some momentum as we begin to get deeper into the year and, while its unknown exactly when, a little but closer to the final XSLT 2.0, XPath 2.0, and XQuery specs, support for which is available for all three in (of course) Saxon and as such Saxon.NET.
This is just a stopping point for the day on a library which has quite a few satellite libraries that add further extension and functionality that are already well under development and will hopefully be available in the next week or two for further consumption and distribution.
Couple things to note. I realized the other day that it really made a lot more sense to move away from the ‘org.x2x2x.Xml’ namespace and instead use ‘Saxon.Xml.Xsl’ as the prior[um, that would be latter would’nt it… oops] fits much more in line with what the project is all about and more directly into the .NET namespace naming conventions instead of the Java classpath conventions. Before I go and make any sort of announcement that this is the final name space usage I will need to run things through both DonXML and Dr. Kay. If things change I will certainly let you know. [PLEASE NOTE: To view the code properly please view this post in its normal .html format… I need to fix the issues with the way code doesnt get handled well on the main page but I am almost done with the next redesign so Its probably not going to happen in the state it lives in now… but the new designs is A LOT better so I think it’ll all be good :)]
Note: the first part of this was commented directly in the code/editor… thus the funky slashes that make things seem abnormal.
// All code has been developed by M. David Peterson for and as part of the Saxon.NET project // What you do with it is up to you. At present time (May 15th, 2005) this is still // under development with fairly extensive planse as far as just how far we plan to take this // project. But this is a decent start at understanding the ins and outs of developing using // Saxon.NET from a C# perspective.
// With TechEd the Birds of a Feather session proposed, planned, // promoted, and etc… by DonXML (given the fact that were 3 weeks away from the start) its obviously // time to put some serious development effort such that there is lots to play with at the BOAF. I have // one other major project that I plan to split my time with Saxon.NET development over the next 3 weeks // which should lend well to probably a good 80-100 hours of devtime before the BOAF session which hopefully // should mean both extensive progress with extension projects as well as Saxon#… Lets hope anyway. :)
// Things to note: // I’ve implemented some of the new functionality provided by the XML-MVP group. In particular I have focused // on XPathNavigatorReader class library for the many nice little touches as well as MAJOR enhancements it has in // regards to pulling some extremely useful features into the XPathDocument arena and as such making it by // far and beyond the definite choice for high powered handling of XML ESPECIALLY in regards to // pipelining as you gain all the speed and realiability of XPathDocument and XPathNavigator with the // cability to gain direct access to the underlying XML for outputting in various regards with ease and // simplicity (which, before this meant basically converting // everything in front of your current Node position to a string for output to a new format and the reloaded into that “version of XML ;)” serilization to then move on to the next item on the list.
// As many of you undoubtedly know when you’re pipelining XML around // from one process to the next theres an obvious disadvantage that comes from conversion from one format to another // ESPECIALLY when a lot of the times this also means losing your current position within the node-set, that if // wasn’t lost would bring you that much more performance gain. This class brings you this, caching and serialization // benefits and… hmmm… theres seems to be something I’m missing. I guess it’ll give you something to // look forward to finding out for yourselves as without a doubt this is something I plan to use A TON // and would recommend to anybody who does a ton of XML work within .NET to consider the same. This is // some really well thought out and implemented code. My hat goess off to the XML-MVP’s for a job EXTREMELY well done!
// First file, Saxon.Xml.Xsl.cs (I’ll provide a zip file of all of this at the bottom of the page)
using System;
using System.IO;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Serialization;
using System.Collections.Specialized;
using Mvp.Xml.Common.XPath;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using javax.xml.transform;
using javax.xml.transform.stream;
using net.sf.saxon;
namespace Saxon.Xml.Xsl
{
[Serializable]
public class XslTransformer : CSharpCodeProvider
{
//Transformation data variables
private string srcXML;
private string srcXSL;
private NameValueCollection xslParams;
//Constructors
public XslTransformer(){ }
public XslTransformer(string srcXML, string srcXSL, NameValueCollection xslParams){
this.srcXML = srcXML;
this.srcXSL = srcXSL;
this.xslParams = xslParams;
}
public void XslParams(NameValueCollection xslParams){
this.xslParams = xslParams;
}
public void XmlDoc(string srcXML){
this.srcXML = srcXML;
}
public void XslDoc(string srcXSL){
this.srcXSL = srcXSL;
}
public XmlReader Transform(){
StreamSource inputXml_Source = new StreamSource(new java.io.FileInputStream(srcXML));
inputXml_Source.setSystemId(srcXML);
StreamSource inputXsl_Source = new StreamSource(new java.io.FileInputStream(srcXSL));
inputXsl_Source.setSystemId(srcXSL);
StringReader reader = new StringReader(DoTransform(inputXml_Source, inputXsl_Source, xslParams));
XPathDocument doc = new XPathDocument(reader);
XPathNavigator nav = doc.CreateNavigator();
XmlReader XPathReader = new XPathNavigatorReader(nav);
return XPathReader;
}
CSharpCodeProvider provider = new CSharpCodeProvider();
//ICodeGenerator generator = provider.CreateGenerator();
protected string DoTransform(StreamSource Xml, StreamSource Xsl, NameValueCollection parameters){
java.lang.System.setProperty("javax.xml.transform.TransformerFactory", "net.sf.saxon.TransformerFactoryImpl");
StreamResult outResult = new StreamResult();
java.io.ByteArrayOutputStream outputXmlResult = new java.io.ByteArrayOutputStream();
outResult.setOutputStream(outputXmlResult);
TransformerFactory trans = TransformerFactory.newInstance();
Transformer transformer = trans.newTransformer(Xsl);
foreach(string paramName in parameters.AllKeys){
string paramValue = parameters.GetValues(paramName)[0];
transformer.setParameter(paramName, paramValue);
}
parameters.Clear();
transformer.transform(Xml, outResult);
return outputXmlResult.toString();
}
}
}
// second files test.aspx
<%@ Page Trace="false" Language="C#" Debug="false"%>
<%@ Import Namespace="System.Xml" %>
<%@ Import Namespace="System.Xml.XPath" %>
<%@ Import Namespace="Saxon.Xml.Xsl" %>
<%@ Import Namespace="System.Collections.Specialized" %>
<script runat="server">
string xmlSource = "./atom.xml";
string xslSource = "./index.xsl";
string transform;
void Page_Load(Object sender, EventArgs e)
{
NameValueCollection xslParams = new NameValueCollection();
xslParams.Add("foo", "test");
xslParams.Add("bar", "test two");
XslTransformer transformer = new XslTransformer();
transformer.XmlDoc(Server.MapPath(xmlSource));
transformer.XslDoc(Server.MapPath(xslSource));
transformer.XslParams(xslParams);
XmlReader resultDoc = transformer.Transform();
buildOutput(resultDoc);
}
void buildOutput (XmlReader resultDoc)
{
Response.ContentType = "text/xml";
XmlTextWriter XWriter = new XmlTextWriter(Response.Output);
XWriter.WriteStartDocument();
XWriter.Formatting = Formatting.Indented;
XWriter.Indentation = 2;
String PItext = "type=\"text/css\" href=\"/xsltblog/ie-namespaces.css\"";
XWriter.WriteProcessingInstruction("xml-stylesheet", PItext);
XWriter.WriteNode(resultDoc, false);
XWriter.Flush();
XWriter.Close();
}
</script>
The MVP-XML Library can be downloaded here.
The sample file
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="foo"/>
<xsl:param name="bar"/>
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="/">
<my:root xmlns:my="http://css.mdptws.com/xsltblog">
<my:tag>This is a normal tag</my:tag>
<my:tag id="red">MY RED TAG</my:tag>
<my:tag id="blue">MY BLUE TAG</my:tag>
<my:tag class="bold">This tag has bold text</my:tag>
<my:tag class="italics">This tag’s text is in italics</my:tag>
<my:tag><xsl:value-of select="$foo"/>hello</my:tag>
<my:tag><xsl:value-of select="$bar"/>hello</my:tag>
</my:root>
</xsl:template>
</xsl:stylesheet>
[UPDATE: I just realized you will need to change the namespace in this file back to the namespace Dean uses, or vise-versa, for this sample to work correctly in your browser] The above is a modification of the IE7 CSS Namespace project from Dean Edwards. As I’m not exactly sure what the distribution terms are in regards to this particular piece, while I have no doubt they’re generous I rather both play it safe as well as send as much recognition as possible to Dean for all of his hard work and effort on all of this. You can find the particular files in question here [NOTE: In particular this is the ie-namespaces.htc project half way down the page, the download link is at the bottom] and the directory for all of his projects here.
By the way, in the ASP.NET sample I just used a random Atom feed that happened to be in the folder I was working in for the source XML as this particular test was focused, for the most part, on getting the little tweaky bugs worked out of implementing a Saxon.NET based transformation and then taking the resulting XML and tie it together within the .NET XML Libraries to be processed further before being output. In particular the issues at hand were:
a) ensuring the proper mime-type was set via the Response.ContentType as Firefox/Mozilla will not foregive you if its not set to text/xml where as IE seems to set this particular piece aside. I can actually understand why as this is one of those support headache deals where you spend half your support budget on explaining to people why and how to change the ContentType in the Response stream — At some point, especially when you have 95% marketshare you have to let go of some of the things that you know are costing you more time, money, and headaches and in reality more damage is being done to the ideals behind standards by the frustration than could ever be gained back by forcing users into banging theirs and your head against the wall for 6 hours until they finally get it or finally give up and curse your very name for years to come. [1]
You cant win.
b) wow, that was off topic. Hmmm… surprising… ;) okay reason 2 for using this as a litmus test (beyond the fact that the effect on the screen kind of has a litmus papers resemblance) was that it was a test in integrating a completely transformed stream from within Saxon.NET, passing it to another process to have an XML declaration and processing instruction added to it such that when it arrived to the end user it would properly render the CSS enhanced XML as opposed to just displaying the text inside of the elements on the screen (as will happen if the right things don’t happen in the right order). This was one a bit more interesting as I spent a good hour or so beating the XML delaration into submission at which point it finally gave in and took its proper position on top of the PI instead of underneath it which, suprisingly, IE was just fine with but Firefox was not.
Shocking.
c) the final test that actually would have been true no matter which direction I chose for the development test was finding a smooth transition from transformation to final output to the Response stream. I found the MVP-XML libraries (or rather used them for the first time) and that was plenty to do the trick. It took some playing to get things to go the way they needed to but the MVP’s have done such a great job of providing comments and samples that most of whats there is (in regards to XPathNavigatorReader) a direct copy and paste and for the most part it just worked. I think the only problem I ran into was I had declared the wrong return type which was my own fault so again, hats off to the MVP’s[left hand side, bottom portion of column] for a job well done!
K, heres the compiled library with the two source files[update:link is fixed and zip now contains C# source where at first I forgot to include it [although it was available to copy and paste of this page so maybe you just did that.] If you downloaded it and found the .cs file missing its there now. Sorry for the hassle!][oops, maybe not… lets see if this one works]. The most recent Saxon.NET bits are from a few days ago and can be downloaded here. As mentioned (and in summary) you will need the MVP-XML Library and the ie-namespaces.htc files from Dean Edwards.
I plan to go underground for a day or two while I focus some serious time on two projects, Saxon.NET and another you don’t know about so I’ll leave the mystery for another exciting day :)
If you have questions please leave comments on this blog for now as it will keep things in one place as opposed to spread out between blogs and various project sites that will probably go unnoticed for a few days if as I tend to lose track of things from time to time. Yep, yet another shocker. ;)
With that, enjoy!
[1][NOTE: The Response.ContentType is different than the “type” attribute as part of the xml-stylesheet processing-instruction which is also an important value but, in reality, for various reasons I doubt we will ever have need to dig any deeper to find out the details, while there is no official text/xsl mime-type this has been the adopted standard for the most part and it will work in both IE and Mozilla as text/xsl and (I believe… Ill have to verify for sure) text/xml. This is actually a dead mime-type as well as things are now moving towards the application/xml+xsl (hmmm… that may not be the right one either… ill need to verify that as well… its close but there seems like somethings missing) mime type which is definitely progress…]
TrackBack URL for this entry:
http://www.xsltblog.com/xslt-blog-mt/mt-tb.cgi/809
Listed below are links to weblogs that reference First real Saxon.NET sample code to play with:
» real estate investing from real estate investing
real estate investing [Read More]
Tracked on February 25, 2006 03:16 PM
» flights russia from flights russia
flights russia [Read More]
Tracked on March 18, 2006 02:47 AM
Hi Mark,
This example is very useful for anyone trying to understand and apply Saxon.NET in .NET.
I am still missing at least one more constructor:
XslTransformer(XPathReader, XPathReader, NameValueCollection)
Cheers, Dimitre Novatchev
Hi Dimitre,
Thanks for this!
In regards to your suggested constructor I currently have under development a class that will take any input for the source - string(XML), string(file), XmlDocument, XPathDocument, XmlReader, XPathReader (the addition to the .NET framework via a separate download from MS), and any other .NET source that can be converted to XML (including the MVP-XML classes) and converts them to an XmlSource data type that is compatible (in fact it extends its directly) with the JAXP StreamSource data type. Using the same class you can then take the ResultSource returned (would need to change this as it currently returns a string) from the DoTransform class and converts it to any of the sources mentioned above.
If you have some time in your schedule it would be great to get some feedback from you in regards to several areas in which are currenty question marks in regards to how to implement. I’ve got a noon delivery and will be gone for a few hours this afternoon. But this evening I plan to put more time into this and it would be fantastic if you had a few minutes to look over my plans and comment as to direction.
Cheers :)
<M:D/>
Hi Mark,
The following like is broken.
http://www.saxondotnet.org/saxon.net/downloads/Saxon.Xml.Xsl.zip
Best, Lalit
Hi Lalit,
I was in a hurry when I approved your comment and didn’t have the time to immediatelly reply. I will look deeper into this and get it fixed.
Thanks for the info!