Tuesday, 7 June 2011

C#.NET 4 - Transforming XML and XSL documents with settings and parameters


This following example takes a path to an XML file, a path to an XSL file and optional parameters to pass to the XSL file. The XSL file will decorate any xsl:param tags with these values.

The example also includes settings objects to show how settings can be applied to the tranformation and the loading of the XML.


Example C# Code
string xsltResult = string.Empty;
 
try
{
    // XML Settings
    XmlReaderSettings xmlSettings = new XmlReaderSettings();
    xmlSettings.XmlResolver = null;
    xmlSettings.IgnoreComments = true;
    xmlSettings.DtdProcessing = DtdProcessing.Ignore;
    xmlSettings.ValidationType = ValidationType.None;
 
    // Attaches an action to the valiation event handler. This will write out error messages in the Output pane.
    #if DEBUG
    xmlSettings.ValidationEventHandler += (sender, e) =>
    {
        Debug.WriteLine(string.Format("{0}({1},{2}): {3} - {4}", e.Exception.SourceUri, e.Exception.LineNumber, e.Exception.LinePosition, e.Severity, e.Message));
    };
    #endif
 
    // XSLT Settings
    XmlReaderSettings xsltSettings = new XmlReaderSettings();
    xsltSettings.XmlResolver = null;
    xsltSettings.DtdProcessing = DtdProcessing.Ignore;
    xsltSettings.ValidationType = ValidationType.None;
 
    // Attaches an action to the valiation event handler. This will write out error messages in the Output pane.
    #if DEBUG
    xsltSettings.ValidationEventHandler += (sender, e) =>
    {
        Debug.WriteLine(string.Format("{0}({1},{2}): {3} - {4}", e.Exception.SourceUri, e.Exception.LineNumber, e.Exception.LinePosition, e.Severity, e.Message));
    };
    #endif
 
    // Init params
    XsltArgumentList xslArgs = new XsltArgumentList();
    if (parameters != null)
    {
        foreach (KeyValuePair<string, string> param in parameters)
            xslArgs.AddParam(param.Key, string.Empty, param.Value);
    }
 
    // Load XML
    using (XmlReader reader = XmlReader.Create(xmlPath, settings))
    {
        // Load XSL
        XsltSettings xslSettings = new XsltSettings(true, true); // Need to enable the document() fucntion
 
        using(XmlReader xslSource = XmlReader.Create(xslPath, xsltSettings))
        {
            XslCompiledTransform xsltDoc = new XslCompiledTransform();
            xsltDoc.Load(xslSource, xslSettings, new XmlUrlResolver());
 
            // Transform
            using (var sw = new UTF8StringWriter())
            {
                        XmlWriterSettings settings = new XmlWriterSettings();
                        settings.Encoding = Encoding.UTF8;
                        settings.OmitXmlDeclaration = true;
 
                using(var xw = XmlWriter.Create(sw,settings))
                {
                    xsltDoc.Transform(reader, xslArgs, sw);
                }
 
                xsltResult = sw.ToString();
            }
        }
    }
}
catch {} // custom error handling here

XSLT - Adding an attribute to an element based on XML data


Adding an attribute to an element requires us to utilise the xsl:attribute element.

Consider the following example:
<img>
  <xsl:attribute name="src">
    <xsl:value-of select="imageURL" />
  </xsl:attribute>
  <xsl:attribute name="alt">
    <xsl:value-of select="altText" />
  </xsl:attribute>
</img>


This will add an src and an alt attribute to an img element; based on the values within the imageURL and altText elements in the XML in this example.


Note: You must make sure that the attributes are added within the element itself. I.e. If the img tag is closed before the attributes are added in the above example, then this would be invalid.

XSLT - Displaying HTML content within XML tags


Rather then using the value-of tag, utilise the copy-of tag instead.


XML File
<?xml version="1.0"?>
<?xml-stylesheet type="text/xml" href="stylesheet.xsl"?>
<test><p><b>This is bold text in a paragraph</b></p></test>



XSL File
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <xsl:copy-of select="test" />
    <xsl:value-of select="test" />
  </xsl:template>
</xsl:stylesheet>



Output

This is bold text in a paragraph


This is bold text in a paragraph

XSLT - Dynamic Grouping Using the Muenchian Method


This blog post describes a full example on how to group XML using the Muenchian Method, using: keys, generate-id() and external parameters [xsl:param] passed into the XSL stylesheet.

My original requirement was to pass in parameters to the XSL file using C# and transform the XML on-the-fly. Therefore, I used xsl:param tags to hold the input values and generate a portion of XML based on this. I had a few problems matching templates and keys based on parameters, as this is not valid.
I therefore, generated by keys based on all the data and filtered the data I required based on the parameters.


The following code describes a full example using: Parameters, Keys and grouping. The aim is to dynamically group events by year and sort them in a descending order.


Grouping.xml
<?xml version="1.0"?>
<?xml-stylesheet type="text/xml" href="stylesheet.xsl"?>
<theme>
    <styles>        
        <style id="style1">
        <title>Test Style 1</title>
            <elements>
                <element id="element1">
                    <title>Test Element 1</title>    
                    <events>
                        <event id="event11" date="2008-10-13">
                            <title>Test Event 1</title>
                        </event>                        
                        <event id="event12" date="2009-03-18">
                            <title>Test Event 2</title>
                        </event>
                        <event id="event13" date="2009-02-26">
                            <title>Test Event 3</title>
                        </event>
                        <event id="event14" date="2011-04-12">
                            <title>Test Event 4</title>
                        </event>
                        <event id="event15" date="2010-01-01">
                            <title>Test Event 5</title>
                        </event>
                        <event id="event16" date="2010-07-06">
                            <title>Test Event 6</title>
                        </event>
                    </events>                                            
                </element>
                <element id="element2">
                    <title>Test Element 2</title>    
                    <events>
                        <event id="event21" date="2001-10-13">
                            <title>Test Event 1</title>
                        </event>                        
                        <event id="event22" date="2001-03-18">
                            <title>Test Event 2</title>
                        </event>
                        <event id="event23" date="2007-02-26">
                            <title>Test Event 3</title>
                        </event>
                        <event id="event24" date="2008-04-12">
                            <title>Test Event 4</title>
                        </event>
                        <event id="event25" date="2010-01-01">
                            <title>Test Event 5</title>
                        </event>
                        <event id="event26" date="2010-07-06">
                            <title>Test Event 6</title>
                        </event>
                    </events>                                            
                </element>
            </elements>                
        </style>
        <style id="style2">
        <title>Test Style 2</title>
            <elements>
                <element id="element3">
                    <title>Test Element 3</title>    
                    <events>
                        <event id="event31" date="2003-10-13">
                            <title>Test Event 1</title>
                        </event>                        
                        <event id="event32" date="2007-03-18">
                            <title>Test Event 2</title>
                        </event>
                        <event id="event33" date="2007-02-26">
                            <title>Test Event 3</title>
                        </event>
                        <event id="event34" date="2010-04-12">
                            <title>Test Event 4</title>
                        </event>
                        <event id="event35" date="2010-01-01">
                            <title>Test Event 5</title>
                        </event>
                        <event id="event36" date="2010-07-06">
                            <title>Test Event 6</title>
                        </event>
                    </events>                                            
                </element>                
            </elements>                
        </style>
    </styles>
</theme>





Stylesheet.xsl
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ms="urn:schemas-microsoft-com:xslt">
 
  <!-- Parameters -->
  <xsl:param name="style">style1</xsl:param>
  <xsl:param name="element">element1</xsl:param>
 
  <!-- Create a key based on the YYYY portion of the start_date attribute -->
  <xsl:key
    name="keyYear"
    match="events/event"
    use="substring(@date, 1, 4)"
  />
  <xsl:key
    name="keyEventID"
    match="events/event"
    use="@id"
  />
 
 
  <!-- Match default template -->
  <xsl:template match="/">
    <xsl:apply-templates select="/theme/styles/style[@id=$style]/elements/element[@id=$element]/events" />
  </xsl:template>
 
 
  <!-- matches on events, so only outputs once [per stream] -->
  <xsl:template match="events">
 
    <table>
      <xsl:for-each select="//event[generate-id()=generate-id(key('keyYear', substring(@date, 1, 4))[1])]">
        <xsl:sort select="substring(@date, 1, 4)" order="descending" />
 
        <!-- Save the Year to a variable -->
        <xsl:variable name="varCurrentYear"><xsl:value-of select="substring(@date, 1, 4)" /></xsl:variable>
        
        <!-- Select all the events belonging to the year -->
        <xsl:variable name="lstEventPerYear" select="/theme/styles/style[@id=$style]/elements/element[@id=$element]/events/event[substring(@date, 1, 4)=$varCurrentYear]" />
        
        <!-- Store child count -->
        <xsl:variable name="varChildCount"><xsl:value-of select="count($lstEventPerYear[generate-id(.) = generate-id(key('keyEventID', @id)[1])])" /></xsl:variable>
 
        <!-- Output year only if there are sub elements -->
        <xsl:if test="$varChildCount > 0">
            <tr>
                <td>
                    <h3><xsl:value-of select="$varCurrentYear" /></h3>
                </td>
            </tr>
          
            <xsl:for-each select="$lstEventPerYear[generate-id(.) = generate-id(key('keyEventID', @id)[1])]">
            <xsl:sort select="title" />     
            <tr>
                <td>
                    <h4>
                        <xsl:value-of select="title" />
                          <xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text>
                        [<xsl:value-of select="ms:format-date(@date, 'dd MMM yyyy')"/>]
                    </h4>
                </td>
            </tr>             
            </xsl:for-each>
        </xsl:if>
      </xsl:for-each>
    </table>
  </xsl:template>
    
</xsl:stylesheet>

Wednesday, 25 May 2011

Developing Facebook Applications locally


Hosts File [C:\Windows\System32\drivers\etc]
1. Edit the windows hosts file

2. Add an entry to map to localhost (127.0.0.1). This url name can be anything, it’s so that when you re-direct your browser to this url, it will forward directly to localhost. This matches the Facebook canvas URL schema that is required.

Example: "127.0.0.1 bigblunts.com" (without quotes)

3. Save and close the hosts file. If you do not have permissions to do this, open Notepad (or any other text editor) as an Administrator, and try again.

4. Open your web browser and go to the url you have just added, the browser should be displaying the same as if your went to http://localhost (This should usually be the IIS homepage).


Web Server Configuration
I personally use .NET and IIS, but you can really use which ever development tools and web servers you like. Just ensure that the application is accessible through the localhost.

So for example, if you access your application via. http://localhost/FacebookApp (Where 'FacebookApp' is the application configured within your webserver) Then using the settings in your hosts file, this will also work for you: http://bigblunts.com/FacebookApp. This will be the URL that you will be adding within your Facebook application settings.


Facebook Settings
1. I usually create a new Facebook application and append "staging" to the name. This saves me having to change canvas urls and other things to point to different environments each time I want to deploy something.


The Facebook settings are as follows [as of May 2011]:
Replace the vales with the name of your webserver path...
[Web Site] > [Site URL] > http://bigblunts.com/FacebookApp/
[Web Site] > [Site Domain] > bigblunts.com
[Facebook Integration] > [Canvas URL] > http://bigblunts.com/FacebookApp/
[Facebook Integration] > [Tab URL] > http://bigblunts.com/FacebookApp/ [When integrating with pages, it'll use this as the menu item/tab name]
[Advanced] > [Sandbox Mode] > Enable [Note: Must only use developer accounts to test with! or you will get errors]


Some of the settings may be irrelevant for your application requirements, but this is where to specify the URLs when these features are required.



!!!!UPDATE!!!!
You can also use the visual studio development server to get around this problem (or any other server, just use port 8080!)

Make sure you run the server on port "8080"... Facebook won't argue with this. (Note: If you use any other port, other than the standard web traffic ports [80/8080], then Facebook will throw a blank proxy dialog at you, with no kind of helpful error messages! The URL will contain something like "xd_proxy"...so make sure it's set at 8080!

The settings you can use are as follows...
[Web Site] > [Site URL] > http://localhost:8080/
[Web Site] > [Site Domain] > localhost
[Facebook Integration] > [Canvas URL] > http://localhost:8080/
[Facebook Integration] > [Tab URL] > http://localhost:8080/
[Advanced] > [Sandbox Mode] > Enable [Note: Must only use developer accounts to test with! or you will get errors]

Friday, 8 April 2011

C#: DescriptionAttribute with Enums


If you've ever created an Enum, usually the entities you define within the enum are not user friendly. I.e. outputting to the console "EnumDescEntityTwo". We would probably prefer it to have whitespaces "Enum Desc Entity Two" or even be called something totally different "Cheese Sandwich".

So there are a few ways to achieve this without writing a bunch of conditions in the GUI layer.


1. Map the Enums to database table.

I.e.
- ID (For DB use only)
- EnumID (Maps onto the Enum value)
- EnumDescription (A description representing the enum)

The only bad thing is that a database call must be made at some point to gather the description. But the good things are that these values will not be hardcoded.



2. Use Attributes

Like any attributes in .NET, we can define a custom attribute class by defining a class and inheriting the "System.Attribute" base class. However, .NET already provides a DescriptionAttribute class for cases like these in the "System.ComponentModel" namespace.

[Example]

a) Define your enum


    using System.ComponentModel;
 
    public enum FoodItems
    {
        [DescriptionAttribute("A Specialist Bacon Roll")]
        BaconRollWithBurgerSauce = 1,
        [DescriptionAttribute("Burning Hot Chilli")]
        HotChilliBurningHot = 2,
        [DescriptionAttribute("Sixty Inch Pizza with Everything!")]
        SixtyInchPizzaWithEverythingOnIt = 3
    }



b) Use reflection to get the description attribute

// Get the descrption attribute for the status
FoodItem item = FoodItem.BaconRollWithBurgerSauce;
FieldInfo fi = typeof(FoodItem).GetField(Enum.GetName(typeof(FoodItem), item));
DescriptionAttribute da = (DescriptionAttribute)fi.GetCustomAttributes(typeof(DescriptionAttribute), false)[0];
string desc = da.Description;

Monday, 28 March 2011

JOINS - Which is which!?


Amazing post about different joins represented by a Venn Diagram.

http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html

Monday, 14 March 2011

T-SQL: How to rename a table or column using T-SQL in Microsoft SQL


So yeah, you could use the Microsoft SQL Server Management Studio UI to rename your table or column. But sometimes you need to do the rename in T-SQL. Here’s how.

How to rename a table:


EXEC sp_rename 'OldTableName','NewTableName'


How to rename a column:

EXEC sp_rename
@objname = 'TableName.OldColumnName',
@newname = 'NewColumnName',
@objtype = 'COLUMN'


For a more detailed explanation of sp_rename check out this MSDN article: http://msdn2.microsoft.com/en-us/library/ms188351.aspx

Friday, 11 March 2011

.NET: Take Securing Web Services With Username and Password One Step Further With a Custom SoapExtension


Brilliant page and explains everything

http://keithelder.net/2007/01/09/

Wednesday, 9 March 2011

LinqToSql: ForeignKeyReferenceAlreadyHasValueException


I recently had an error with a project while attempting to modify a foreign key for a database object. Quite simply, once the foreign key was established, if any chances were made to it, it would throw this exception. This is correct by design! So in theory, the initial insert is fine, but any update made will throw this error.

The resolve this issue, open up the linq designer file (dbml) and modify the association between the table and its foreign counterpart. If you set 'Child Property' to true, this will allow you to add this association as a property to the database object for your class.

So in the code, instead of editing the foreign key

i.e. Object.ForeignKeyID = id;

You need to make a call using the same data context to retrieve the object, and set it to the property you have just created for your assoication.

i.e. Object.AssociationName = dataContext.Table.Single(val = val.id == idhere);