logo

XMLHelper Redux
and the IE WebBrowser Control in .NET

By Peter A. Bromberg, Ph.D.
Printer-Friendly Version

Peter Bromberg

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 = oI
nnerHTML 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

 
Do you have a question or comment about this article? Have a programming problem you need to solve? Post it at eggheadcafe.com forums and receive immediate email notification of responses.