Saturday, February 28, 2009

TransformXml - A quick app to transform an xml file with an xsl file.

This is a real quick and dirty way to transform an XML file using an XSL file.

using System;
using System.Xml;
using System.Xml.Xsl;

namespace TransformXml
{
 class Program
 {
  static void Main(string[] args)
  {
   if (args.Length != 3)
   {
    Console.WriteLine("TransformXml Usage:");
    Console.WriteLine("  TransformXml.exe <source xml file> <xsl file> <output file>");
    return;
   }

   string sourceXmlFile = args[0];
   string xslFile = args[1];
   string outputFile = args[2];

   XslCompiledTransform t = new XslCompiledTransform();

   t.Load(xslFile);

   t.Transform(sourceXmlFile, outputFile);
  }
 }
}

RPT to CSV

A simple console application to convert the fixed-width output from the "Output to File" option in SQL Server Management Studio to a CSV file that is actually useful.

I use this instead of the CSV setting in Management Studio because I like seeing the "Output to Text" option in fixed-width format.

This application will not work if the output has newlines or carriage returns in it.

namespace RptToCsv
{
    using System;
    using System.IO;

    /// <summary>
    /// The main class for the RptToCsv program.
    /// </summary>
    public class Program
    {
        /// <summary>
        /// The main entry point to the application.
        /// </summary>
        /// <param name="args">Command line arguments.</param>
        internal static void Main(string[] args)
        {
            if (args.Length > 0)
            {
                for (int i = 0; i < args.Length; i++)
                {
                    string inputFile;
                    string outputFile;

                    inputFile = args[i];
                    outputFile = Path.GetFileNameWithoutExtension(args[i]) + ".csv";

                    Environment.CurrentDirectory = Path.GetDirectoryName(inputFile).Length == 0 ? Environment.CurrentDirectory : Path.GetFullPath(Path.GetDirectoryName(inputFile));

                    using (StreamReader inputReader = File.OpenText(inputFile))
                    {
                        string firstLine = inputReader.ReadLine();
                        string secondLine = inputReader.ReadLine();

                        string[] underscores = secondLine.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

                        string[] fields = new string[underscores.Length];
                        int[] fieldLengths = new int[underscores.Length];

                        for (int j = 0; j < fieldLengths.Length; j++)
                        {
                            fieldLengths[j] = underscores[j].Length;
                        }

                        int fileNumber = 0;

                        StreamWriter outputWriter = null;

                        try
                        {
                            outputWriter = File.CreateText(outputFile.Insert(outputFile.LastIndexOf("."), "_" + fileNumber.ToString()));
                            fileNumber++;

                            int lineNumber = 0;

                            WriteLineToCsv(outputWriter, fieldLengths, firstLine);
                            lineNumber++;

                            string line;

                            while ((line = inputReader.ReadLine()) != null)
                            {
                                if (lineNumber >= 65536)
                                {
                                    outputWriter.Close();
                                    outputWriter = File.CreateText(outputFile.Insert(outputFile.LastIndexOf("."), "_" + fileNumber.ToString()));
                                    fileNumber++;

                                    lineNumber = 0;

                                    WriteLineToCsv(outputWriter, fieldLengths, firstLine);
                                    lineNumber++;
                                }

                                if (!WriteLineToCsv(outputWriter, fieldLengths, line))
                                {
                                    break;
                                }

                                lineNumber++;
                            }
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(ex);
                            Console.WriteLine("NOTE: Input file must not have any newline characters as field contents.");
                            Console.WriteLine();
                            Console.WriteLine("Press any key to continue...");
                            Console.ReadKey(true);
                        }
                        finally
                        {
                            if (outputWriter != null)
                            {
                                outputWriter.Close();
                            }
                        }

                        // If we only had one file created, we don't need the file number in the name.
                        if (fileNumber == 1)
                        {
                            try
                            {
                                if (File.Exists(outputFile))
                                {
                                    File.Delete(outputFile);
                                }

                                File.Move(outputFile.Insert(outputFile.LastIndexOf("."), "_0"), outputFile);
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine(ex);
                                Console.WriteLine("Press any key to continue...");
                                Console.ReadKey(true);
                            }
                        }
                    }
                }
            }
            else
            {
                Console.WriteLine("Converts the ouput of a SQL Server Management Studio .rpt file to a CSV file.");
                Console.WriteLine("You can generate a .rpt file by selecting \"Results to File\" in the toolbar.");
                Console.WriteLine();
                Console.WriteLine("Usage: RptToCsv.exe <inputFile1> [<inputFile2> ...]");
                return;
            }
        }

        /// <summary>
        /// Converts a single line of fixed width fields to a single line of comma separated fields.
        /// </summary>
        /// <param name="outputWriter">The stream to write to.</param>
        /// <param name="fieldLengths">An array containing the lengths of the fixed with fields.</param>
        /// <param name="line">The line of fixed width fields to be converted to CSV.</param>
        /// <returns>True if it successfully converts the line, otherwise False.</returns>
        private static bool WriteLineToCsv(StreamWriter outputWriter, int[] fieldLengths, string line)
        {
            if (line.Length == 0)
            {
                return false;
            }

            int index = 0;

            for (int i = 0; i < fieldLengths.Length; i++)
            {
                string value;

                if (i < fieldLengths.Length - 1)
                {
                    value = line.Substring(index, fieldLengths[i]);
                }
                else
                {
                    value = line.Substring(index);
                }

                value = value.Replace("\"", "\"\"");
                value = value.Trim();

                if (value == "NULL")
                {
                    value = string.Empty;
                }

                outputWriter.Write("\"{0}\"", value);
                index += fieldLengths[i] + 1;

                if (i < fieldLengths.Length - 1)
                {
                    outputWriter.Write(",");
                }
                else
                {
                    outputWriter.WriteLine();
                }
            }

            return true;
        }
    }
}

xLibrary - Using a custom IHttpHandler to access embedded javascript

I have written an article at CodeProject.com showing in depth how to embed your JavaScript files in your ASP.Net assemblies and how to implement IHttpHandler to get them out.

Cross Site Scripting...

Have you ever absolutely needed to do an AJAX call to another domain? Here is a way to do it (non-secure). Basically, we create a new IHttpHandler that listens for a request. It takes a single QueryString parameter, "url". It then passes the request on to the given destination. It supports all HTTP Methods (GET, PUT, HEAD, POST, etc.).

First, create a new class that implements IHttpHandler as follows:

CrossDomainHandler.ashx.cs

using System;
using System.Globalization;
using System.IO;
using System.Net;
using System.Web;

namespace CrossDomain
{
 public class CrossDomainHandler : IHttpHandler
 {
  public CrossDomainHandler()
  {
  }

  public void ProcessRequest(HttpContext context)
  {
   try
   {
    string url = context.Request.QueryString["url"];

    HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;

    request.Headers.Clear();

    foreach (string key in context.Request.Headers.AllKeys)
    {
     string value = context.Request.Headers[key];

     if (string.Compare(key, "Connection", true, CultureInfo.InvariantCulture) == 0)
     {
      if (string.Compare(value, "Keep-Alive", true, CultureInfo.InvariantCulture) == 0)
      {
       request.KeepAlive = true;
      }
      else if (string.Compare(value, "Close", true, CultureInfo.InvariantCulture) == 0)
      {
       request.KeepAlive = false;
      }
      else
      {
       request.Connection = value;
      }
     }
     else if (string.Compare(key, "Content-Length", true, CultureInfo.InvariantCulture) == 0)
     {
      int length = Convert.ToInt32(value);

      if (length > 0)
      {
       request.ContentLength = length;
      }
     }
     else if (string.Compare(key, "Accept", true, CultureInfo.InvariantCulture) == 0)
     {
      request.Accept = value;
     }
     else if (string.Compare(key, "Content-Type", true, CultureInfo.InvariantCulture) == 0)
     {
      request.ContentType = value;
     }
     else if (string.Compare(key, "Date", true, CultureInfo.InvariantCulture) == 0)
     {
     }
     else if (string.Compare(key, "Expect", true, CultureInfo.InvariantCulture) == 0)
     {
      request.Expect = value;
     }
     else if (string.Compare(key, "Host", true, CultureInfo.InvariantCulture) == 0)
     {
     }
     else if (string.Compare(key, "If-Modified-Since", true, CultureInfo.InvariantCulture) == 0)
     {
      request.IfModifiedSince = DateTime.Parse(value);
     }
     else if (string.Compare(key, "Proxy-Connection", true, CultureInfo.InvariantCulture) == 0)
     {
     }
     else if (string.Compare(key, "Range", true, CultureInfo.InvariantCulture) == 0)
     {
     }
     else if (string.Compare(key, "Referer", true, CultureInfo.InvariantCulture) == 0)
     {
      request.Referer = value;
     }
     else if (string.Compare(key, "Transfer-Encoding", true, CultureInfo.InvariantCulture) == 0)
     {
      request.TransferEncoding = value;
     }
     else if (string.Compare(key, "User-Agent", true, CultureInfo.InvariantCulture) == 0)
     {
      request.UserAgent = value;
     }
     else
     {
      request.Headers.Add(key, value);
     }
    }

    request.Method = context.Request.HttpMethod;

    if (context.Request.ContentLength > 0)
    {
     CopyStream(context.Request.InputStream, request.GetRequestStream(), 512);
    }

    using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
    {
     context.Response.ClearHeaders();
     context.Response.ClearContent();

     foreach (string key in response.Headers.AllKeys)
     {
      context.Response.AddHeader(key, response.Headers[key]);
     }

     if (response.ContentLength > 0)
     {
      CopyStream(response.GetResponseStream(), context.Response.OutputStream, 512);
     }
    }
   }
   catch (Exception ex)
   {
    context.Response.Write(ex);
   }
  }

  public bool IsReusable
  {
   get
   {
    return false;
   }
  }

  private static void CopyStream(Stream input, Stream output, int bufferSize)
  {
   byte[] buffer = new byte[bufferSize];
   int count = 0;

   while ((count = input.Read(buffer, 0, buffer.Length)) > 0)
   {
    output.Write(buffer, 0, count);
   }
  }

 }
}

CrossDomainHandler.ashx

<%@ WebHandler Class="CrossDomain.CrossDomainHandler,CrossDomain" %>

Use it as follows:

if (typeof XMLHttpRequest == "undefined") XMLHttpRequest = function() {
  try { return new ActiveXObject("Msxml2.XMLHTTP.6.0") } catch(e) {}
  try { return new ActiveXObject("Msxml2.XMLHTTP.3.0") } catch(e) {}
  try { return new ActiveXObject("Msxml2.XMLHTTP") } catch(e) {}
  try { return new ActiveXObject("Microsoft.XMLHTTP") } catch(e) {}
  throw new Error("This browser does not support XMLHttpRequest.")
};

var req = new XMLHttpRequest();

req.open('GET', 'CrossDomainHandler.ashx?url=http%3A%2F%2Fwww.google.com%2F', false);

alert(req.responseText);

Or, extending the Prototype JS Framework:

CrossDomainAjax.js

Ajax.CrossDomainRequest = Class.create(Ajax.Request, {
 initialize: function($super, url, handlerUrl, options) {
  this.handlerUrl = handlerUrl;
  $super(url, options);
 },
 request: function($super, url) {
  this.url = url;
  if (!this.isSameOrigin())
   url = this.handlerUrl + '?url=' + encodeURIComponent(url);
  $super(url);
 }
});

To use:

<script type="text/javascript">
var mine = new Ajax.CrossDomainRequest('http://www.google.com/', 'CrossDomainHandler.ashx', {
 method: 'head',
 onSuccess: function(transport) {
  $('mine').value = transport.getAllResponseHeaders();
 }
});
</script>

Hope this helps…