tags:

views:

2518

answers:

5

Hi Everyone,

I'd like to do the following and can't find an elegant way:

1) Read an XML template into a System.Xml.XmlDocument
2) Populate it with data from my UI
3) Transform it with an XSLT I've written
4) Apply a CSS Stylesheet
5) Render it to a WebBrowser control

I'm currently reading it from a file on disk, populating it, then saving it back out to disk after populating it. I reference the XSLT in the template, and the CSS in the XSLT and then use the WebBrowser.Navigate([filename]) method to display the XML file.

Obviously, when I come to deploy this app, it'll break horribly as the file won't exist on disk, and I won't be able to reference the XSLT and CSS files in the XML file as they'll be resources. I'm planning to include the template as a resource, but can't find a neat way to proceed from there.

Any help much appreciated,
Jon

+1  A: 

Quick question. Why do you need an Xml template? If you already know the schema before hand, then simply generate the complete Xml in your code. There shouldn't be a need for loading a template file.

Vaibhav
A: 

I've got to confess, this is my first time working with XML from scratch so I wasn't entirely sure whether I needed a schema or not. This is a very simple template, as I'm really just looking for a nice way to render about 15 properties in a user-friendly format to give a summary of the data entered. I was attracted to XML as the xsl:for-each function makes my life very easy.

I currently define the elements I need as follows:

<!DOCTYPE mydoc [ <!ELEMENT element1 ANY> <!ELEMENT element2 ANY> ... ] >

Then the template is a really simple format for me to hang data off:

<MyDoc>
<element1></element1>
<element2></element2>
</MyDoc>

Is there a better way of doing this?

Thanks for the quick reply!
Jon

Jon Artus
A: 

Check out Linq to XML - it's really good way to write and read Xml based data. Easier than the System.Xml.XmlDocument mechanisms.

Given that you are supplying the XSLT and the CSS, why not build the page in XHTML and inline the CSS? Alternatively just add the XSLT and CSS files as content in your installer.

Compiled help actually does something like what you're describing - you can copy a link from a CHM file and visit it with a normal browser. I suppose you could embed your display resources in a help file, depending on how they're used.

Keith
A: 

Thanks for the link Keith, I'll have a look at that out of interest, as LINQ is on my list of things to learn. Unfortunately, I need to target .Net 2.0 for this app, so I think (please correct me if I'm wrong!) that LINQ is out of the question.

I've now included the CSS in the header of the XSLT, and I've found a way to use a System.Xml.Xsl.XslCompiledTransform object to transform the XML in memory. I'm currently using the WebBrowser.DocumentText property to pass the formatted XML into the WebBrowser componenet and this seems to work.

I can't help thinking that this isn't the best way of doing things, so any comments on better ways would be appreciated. In particular, if I were using LINQ, would I need a schema to bind to, and also, should I have a schema full-stop? I'm not great with XML, but I like Vaibhav's idea of generating straight from a schema rather than using a template. I'm just not sure where to start, so any pointers appreciated!

Jon Artus
A: 

Because you are using the WebBrowser control and not WPF you must depend on the disk for loading the CSS file you mention in Step 4. The only way around this is to use a tool like Resource Hacker to load "unmanaged" resources and use the res:// protocol (http://msdn.microsoft.com/en-us/library/aa767740(VS.85).aspx) for some real Microsoft 1990s nostalgia.

You will still need to get your data into HTML elements. The code sample that follows might help to answer something:

void WireUpBrowserEvents()
{

    HtmlElement table = this._browser.Document.GetElementById( "UnitFormsTable" );
    if ( table != null )
    {
        HtmlElementCollection thead = table.GetElementsByTagName( "thead" );
        if ( ( thead != null ) && ( thead.Count == 1 ) )
        {
            HtmlElementCollection links = thead[0].GetElementsByTagName( "a" );
            if ( ( links != null ) && ( links.Count > 0 ) )
            {
                foreach ( HtmlElement a in links )
                {
                    a.Click += new HtmlElementEventHandler( XslSort_Click );
                }
            }
        }
    }
}

void XslSort_Click( object sender, HtmlElementEventArgs e )
{
    e.ReturnValue = false;

    if ( this._xslSortWorker.IsBusy ) return;

    if ( sender is HtmlElement )
    {
        HtmlElement a = sender as HtmlElement;
        this._browser.Hide();
        this._browserMessage.Visible = true;
        this._browserMessage.Refresh();
        this._xslSortWorker.RunWorkerAsync( a.Id );
    }
}

You may already be aware that HtmlElement and HtmlElementCollection are in the System.Windows.Forms namespace. These remarks may not be helpful but I tried:)

rasx