|
Rob Birdwell has a "work in progress"
on his site he calls "XmlHelper".
Anyone that's familiar with Microsoft's "Application Blocks"
best practices .NET code for Data Access will recognize the familiarity
of the name from their "SqlHelper" assembly (one that I use
quite a bit).
"Xmlhelper" basically is a class
that attempts to encapsulate some of the most common methods used in working
with XML and to provide an additional layer of abstraction, making these
tasks easier. I downloaded XMLHelper and saw that Rob had really put quite
a bit into it. However, I needed to do things like XSL transforms and
Schema validation and none of that stuff was in there.
Rather than roll my own, I decided it would
be better to extend Rob's excellent foundation, add to it, and then make
it available to others to do the same. (I hope that if you do extend the
class, you'll either post some code or a link here at eggheadcafe.com
so others can benefit).
I've added the following functions:
|
///
/// Transform Xml with xsl from URI (filesystem or HTTP), returns a string
///
///
///
///
public string XslTransformURI(string xmlUrl ,string xslUrl )
{
try
{
System.IO.StringWriter stWrite = new System.IO.StringWriter();
XslTransform myXslTransform =new XslTransform();
XPathDocument myXPathDocument = new XPathDocument(xmlUrl);
myXslTransform.Load(xslUrl);
myXslTransform.Transform(myXPathDocument, null, stWrite);
return stWrite.ToString();
}
catch (Exception e)
{
return e.Message;
}
}
///
/// Transform xml / xsl both passed in as strings, returns a string
///
///
///
///
public string XslTransform(string strXmlDoc ,string strXslDoc )
{
try
{
XmlDocument xslDoc = new XmlDocument();
xslDoc.LoadXml(strXslDoc);
XmlDocument xmlDoc =new XmlDocument();
xmlDoc.LoadXml(strXmlDoc);
System.IO.StringWriter stWrite = new System.IO.StringWriter();
XslTransform myXslTransform =new XslTransform();
myXslTransform.Load((System.Xml.XPath.IXPathNavigable)xslDoc);
myXslTransform.Transform(xmlDoc, null, stWrite);
return stWrite.ToString();
}
catch (Exception e)
{
return e.Message;
}
}
///
/// Transform xml / xsl passed in as XmlDocuments, return result as string
///
///
///
///
public string XslTransform(XmlDocument xmlDoc ,XmlDocument xslDoc )
{
try
{
System.IO.StringWriter stWrite = new System.IO.StringWriter();
XslTransform myXslTransform =new XslTransform();
myXslTransform.Load((System.Xml.XPath.IXPathNavigable)xslDoc);
myXslTransform.Transform(xmlDoc, null, stWrite);
return stWrite.ToString();
}
catch(Exception e)
{
return e.Message;
}
}
public static string strValidationErrors=null;
public static int intNumValidationErrors=0;
///
/// Read XmlDocument and apply validation Schema from supplied URIs
///
///
///
///
///
///
public string XmlReadValidate(string strXmlPath , string strSchemaPath, ValidationType enmValidationType, string strTargetNamespace)
{
XmlTextReader tr=new XmlTextReader(strXmlPath);
XmlValidatingReader trv=new XmlValidatingReader(tr);
XmlDocument xmlDoc = new XmlDocument();
XmlSchemaCollection objSchemaCol = new XmlSchemaCollection();
switch(enmValidationType)
{
case ValidationType.Auto :
trv.ValidationType=ValidationType.Auto;
break;
case ValidationType.DTD :
trv.ValidationType=ValidationType.DTD;
break;
case ValidationType.None:
trv.ValidationType=ValidationType.None;
break;
case ValidationType.Schema :
trv.ValidationType=ValidationType.Schema;
break;
case ValidationType.XDR :
trv.ValidationType=ValidationType.XDR;
break;
default:
trv.ValidationType=ValidationType.None;
break;
}
trv.ValidationEventHandler += new ValidationEventHandler(this.ValidationEvent);
if(trv.ValidationType==ValidationType.Schema || trv.ValidationType==ValidationType.XDR)
{
objSchemaCol.Add(strTargetNamespace,strSchemaPath);
trv.Schemas.Add(objSchemaCol);
xmlDoc.Load(trv);
}
if(intNumValidationErrors ==0)
{
return xmlDoc.OuterXml;
}
else
{
return intNumValidationErrors.ToString() +" Validation Errors: " +strValidationErrors;
}
}
public void ValidationEvent(object sender, ValidationEventArgs args)
{
intNumValidationErrors++;
strValidationErrors += " Severity: " +args.Severity + " \n" ;
strValidationErrors+= " at Line: " +args.Exception.LineNumber + " Pos: " +args.Exception.LinePosition ;
}
|
Notice there are two overloads of the XSLTransform function,
one to accept strings and the other XmlDocuments. The XSLTransformURI
function is a variant of the same function that allows either Http or
filesystem loading via URIs. And finally, the XMLReadValidate function
provides for Schema, XDR, or DTD validation of the loaded document. I'm
using a ValidationEvent handler during the validation process to allow
the entire document to be validated. If there are no errors, the OuterXml
of the document is returned, otherwise a detailed ValidationErrors information
string is returned.
Finally, in my "Test Harness" WinForms app
that accompanies the program, I illustrate how to import the IE Webbrowser
control as an alternative to a TextBox in order to render transformed
HTML or XML Documents. There are a lot of posts in the newsgroups asking
how to use the WebBrowser control in .NET, there is no equivalent WebForm
or WinForms control.
The trick with the WebBrowser control is that you can
only access the Document Object as a WebBrowserEvents2_NavigateComplete2Event.
So the trick here is to create global variable for the Document and innerHTML
properties, and then you can modify the innerHTML within the eventhandler.
That's in VB.NET, in C# its' quite a bit more complex. The COM dll for
the WebBrowser control, when you set a COM reference in the Visual Studio.NET
IDE, is "ShDocVW.dll", and it's located in your WINNT\System32
folder.
Dim oDocument As Object
Dim oInnerHTML As String
Private Sub Button1_Click(ByVal sender As System.Object,_ ByVal e As System.EventArgs) Handles Button1.Click
Dim x As PAB.Util.XmlHelper = New PAB.Util.XmlHelper()
Dim strAppPath As String = System.AppDomain.CurrentDomain.BaseDirectory.ToString() & "\"
oInnerHTML = x.XmlReadValidate(strAppPath & "books.xml", _
strAppPath & "books.xsd", Xml.ValidationType.Schema, "urn:bookstore-schema")
AxWebBrowser1.Navigate("about:blank")
End Sub
Private Sub AxWebBrowser1_NavigateComplete2(ByVal sender As Object, _
ByVal e As AxSHDocVw.DWebBrowserEvents2_NavigateComplete2Event) _
Handles AxWebBrowser1.NavigateComplete2
oDocument = e.pDisp.Document
oDocument.body.innerHTML = oInnerHTML
End Sub
|
| |
The "e.pDisp" is a pointer to the IDispatch
interface of the window or frame in which the document has loaded. This
IDispatch interface can be queried for the IWebBrowser2 interface.
The only other change I've made is to shorten Rob's long
namespace declaration. I like to use my initials, so the namespace in
the code for the download is "PAB.Util". Of course, you can
use any namespace you like.
I hope you find the revised XMLHelper class to be instructive
and useful. I know it was for me!
Download
the code that accompanies this article
Peter Bromberg is an independent consultant specializing in distributed .NET solutions
Inc. in Orlando and a co-developer of the EggheadCafe.com
developer website. He can be reached at pbromberg@yahoo.com
|