Click here to Skip to main content
15,886,590 members
Articles / Programming Languages / XML

XML Alphabetizer

Rate me:
Please Sign up or sign in to vote.
4.53/5 (13 votes)
8 Mar 2011CPOL4 min read 96.6K   5.6K   19  
This project will allow the user to alphabetize any XML file without having to translate that file using XSLT or modify it in any way other than ordering nodes based on the names of the nodes themselves or based on an attribute of any node.
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Xsl;
using System.Xml.XPath;
using System.Xml.Linq;
using System.Collections.Generic;

namespace Alphabetizer
{
    /// <summary>
    /// Summary description for the XML Alphabetizer.
    /// </summary>
    public class XMLAlphabetizer : System.Windows.Forms.Form
    {
        #region Private Members
        private System.Windows.Forms.TextBox txtSource;
        private System.Windows.Forms.Label lblSource;
        private System.Windows.Forms.Button btnGenerate;
        private String sourceDoc = "";
        private String resultDoc = "result.xml";
        private System.Windows.Forms.TextBox txtResult;
        private System.Windows.Forms.Button btnReset;
        private OpenFileDialog openFileDialog;
        private Button btnBrowse;
        private Label lblDepth;
        private NumericUpDown numericUpDown;
        private Label lblSort;
        private TextBox txtAttribute;
        private GroupBox grpOrder;
        private ComboBox comboBox1;

        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;
        #endregion
        
        #region Constructor
        public XMLAlphabetizer()
        {
            //
            // Required for Windows Form Designer support
            //
            InitializeComponent();

            //
            // TODO: Add any constructor code after InitializeComponent call
            //
        } 
        #endregion

        #region Dispose
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (components != null)
                {
                    components.Dispose();
                }
            }
            base.Dispose(disposing);
        } 
        #endregion

        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.txtSource = new System.Windows.Forms.TextBox();
            this.lblSource = new System.Windows.Forms.Label();
            this.btnGenerate = new System.Windows.Forms.Button();
            this.txtResult = new System.Windows.Forms.TextBox();
            this.btnReset = new System.Windows.Forms.Button();
            this.openFileDialog = new System.Windows.Forms.OpenFileDialog();
            this.btnBrowse = new System.Windows.Forms.Button();
            this.lblDepth = new System.Windows.Forms.Label();
            this.numericUpDown = new System.Windows.Forms.NumericUpDown();
            this.lblSort = new System.Windows.Forms.Label();
            this.txtAttribute = new System.Windows.Forms.TextBox();
            this.grpOrder = new System.Windows.Forms.GroupBox();
            this.comboBox1 = new System.Windows.Forms.ComboBox();
            ((System.ComponentModel.ISupportInitialize)(this.numericUpDown)).BeginInit();
            this.grpOrder.SuspendLayout();
            this.SuspendLayout();
            // 
            // txtSource
            // 
            this.txtSource.Location = new System.Drawing.Point(79, 14);
            this.txtSource.Name = "txtSource";
            this.txtSource.Size = new System.Drawing.Size(304, 20);
            this.txtSource.TabIndex = 1;
            // 
            // lblSource
            // 
            this.lblSource.Location = new System.Drawing.Point(12, 18);
            this.lblSource.Name = "lblSource";
            this.lblSource.Size = new System.Drawing.Size(84, 20);
            this.lblSource.TabIndex = 0;
            this.lblSource.Text = "Source XML";
            // 
            // btnGenerate
            // 
            this.btnGenerate.Location = new System.Drawing.Point(389, 47);
            this.btnGenerate.Name = "btnGenerate";
            this.btnGenerate.Size = new System.Drawing.Size(63, 20);
            this.btnGenerate.TabIndex = 8;
            this.btnGenerate.Text = "Generate";
            this.btnGenerate.Click += new System.EventHandler(this.btnGenerate_Click);
            // 
            // txtResult
            // 
            this.txtResult.Location = new System.Drawing.Point(13, 103);
            this.txtResult.Multiline = true;
            this.txtResult.Name = "txtResult";
            this.txtResult.ReadOnly = true;
            this.txtResult.ScrollBars = System.Windows.Forms.ScrollBars.Both;
            this.txtResult.Size = new System.Drawing.Size(451, 276);
            this.txtResult.TabIndex = 10;
            // 
            // btnReset
            // 
            this.btnReset.DialogResult = System.Windows.Forms.DialogResult.Cancel;
            this.btnReset.Location = new System.Drawing.Point(389, 77);
            this.btnReset.Name = "btnReset";
            this.btnReset.Size = new System.Drawing.Size(63, 20);
            this.btnReset.TabIndex = 9;
            this.btnReset.Text = "Reset";
            this.btnReset.Click += new System.EventHandler(this.btnReset_Click);
            // 
            // openFileDialog
            // 
            this.openFileDialog.FileName = "openFileDialog";
            this.openFileDialog.Filter = "XML files (*.xml)|*.xml|Text files (*.txt)|*.txt|All files (*.*)|*.*";
            this.openFileDialog.InitialDirectory = ".";
            // 
            // btnBrowse
            // 
            this.btnBrowse.Location = new System.Drawing.Point(389, 13);
            this.btnBrowse.Name = "btnBrowse";
            this.btnBrowse.Size = new System.Drawing.Size(66, 20);
            this.btnBrowse.TabIndex = 2;
            this.btnBrowse.Text = "Browse...";
            this.btnBrowse.UseVisualStyleBackColor = true;
            this.btnBrowse.Click += new System.EventHandler(this.btnBrowse_Click);
            // 
            // lblDepth
            // 
            this.lblDepth.AutoSize = true;
            this.lblDepth.Location = new System.Drawing.Point(12, 47);
            this.lblDepth.Name = "lblDepth";
            this.lblDepth.Size = new System.Drawing.Size(181, 13);
            this.lblDepth.TabIndex = 3;
            this.lblDepth.Text = "Minimum Tree Depth to Apply Sort At";
            // 
            // numericUpDown
            // 
            this.numericUpDown.Location = new System.Drawing.Point(199, 45);
            this.numericUpDown.Name = "numericUpDown";
            this.numericUpDown.Size = new System.Drawing.Size(59, 20);
            this.numericUpDown.TabIndex = 4;
            // 
            // lblSort
            // 
            this.lblSort.AutoSize = true;
            this.lblSort.Location = new System.Drawing.Point(12, 77);
            this.lblSort.Name = "lblSort";
            this.lblSort.Size = new System.Drawing.Size(114, 13);
            this.lblSort.TabIndex = 5;
            this.lblSort.Text = "Sort By Attribute Name";
            // 
            // txtAttribute
            // 
            this.txtAttribute.Location = new System.Drawing.Point(132, 74);
            this.txtAttribute.Name = "txtAttribute";
            this.txtAttribute.Size = new System.Drawing.Size(126, 20);
            this.txtAttribute.TabIndex = 6;
            // 
            // grpOrder
            // 
            this.grpOrder.Controls.Add(this.comboBox1);
            this.grpOrder.Location = new System.Drawing.Point(275, 40);
            this.grpOrder.Name = "grpOrder";
            this.grpOrder.Size = new System.Drawing.Size(108, 54);
            this.grpOrder.TabIndex = 7;
            this.grpOrder.TabStop = false;
            this.grpOrder.Text = "Sort Attributes";
            // 
            // comboBox1
            // 
            this.comboBox1.FormattingEnabled = true;
            this.comboBox1.Items.AddRange(new object[] {
            "None",
            "Ascending",
            "Decending"});
            this.comboBox1.Location = new System.Drawing.Point(6, 19);
            this.comboBox1.Name = "comboBox1";
            this.comboBox1.Size = new System.Drawing.Size(96, 21);
            this.comboBox1.TabIndex = 0;
            this.comboBox1.Text = "None";
            // 
            // XMLAlphabetizer
            // 
            this.AcceptButton = this.btnGenerate;
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.CancelButton = this.btnReset;
            this.ClientSize = new System.Drawing.Size(476, 391);
            this.Controls.Add(this.grpOrder);
            this.Controls.Add(this.txtAttribute);
            this.Controls.Add(this.lblSort);
            this.Controls.Add(this.numericUpDown);
            this.Controls.Add(this.lblDepth);
            this.Controls.Add(this.txtSource);
            this.Controls.Add(this.btnBrowse);
            this.Controls.Add(this.btnReset);
            this.Controls.Add(this.txtResult);
            this.Controls.Add(this.btnGenerate);
            this.Controls.Add(this.lblSource);
            this.Name = "XMLAlphabetizer";
            this.Text = "XML Alphabetizer";
            ((System.ComponentModel.ISupportInitialize)(this.numericUpDown)).EndInit();
            this.grpOrder.ResumeLayout(false);
            this.ResumeLayout(false);
            this.PerformLayout();

        }
        #endregion

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.Run(new XMLAlphabetizer());
        }

        #region Public Method - RunSort
        /// <summary>
        /// Run the sorting routine for the XML document.
        /// </summary>
        /// <param name="sourceDoc"></param>
        /// <returns></returns>
        public XDocument RunSort(string sourceDoc, int level, string attribute, int sortAttributes)
        {
            XDocument doc = XDocument.Load(sourceDoc);

            //Add these two hard-coded values as options from within the UI so we can apply it to any XML file.
            XDocument sortedDoc = Sort(doc, level, attribute, sortAttributes);

            XmlWriterSettings settings = new XmlWriterSettings();
            settings.OmitXmlDeclaration = true;
            settings.Indent = true;

            using (XmlWriter writer = XmlWriter.Create(resultDoc, settings))
            {
                sortedDoc.WriteTo(writer);
            }
            return sortedDoc;
        } 
        #endregion

        #region Private Method - Sort
        /// <summary>
        /// Sort an XML Element based on a minimum level to perform the sort from and either based on the value
        /// of an attribute of an XML Element or by the name of the XML Element.
        /// </summary>
        /// <param name="file">File to load and sort</param>
        /// <param name="level">Minimum level to apply the sort from.  0 for root level.</param>
        /// <param name="attribute">Name of the attribute to sort by.  "" for no sort</param>
        /// <param name="sortAttributes">Sort attributes none, ascending or decending for all sorted XML nodes</param>
        /// <returns>Sorted XElement based on the criteria passed in.</returns>
        private static XDocument Sort(XDocument file, int level, string attribute, int sortAttributes)
        {
            return new XDocument(Sort(file.Root, level, attribute, sortAttributes));
        }
        /// <summary>
        /// Sort an XML Element based on a minimum level to perform the sort from and either based on the value
        /// of an attribute of an XML Element or by the name of the XML Element.
        /// </summary>
        /// <param name="element">Element to sort</param>
        /// <param name="level">Minimum level to apply the sort from.  0 for root level.</param>
        /// <param name="attribute">Name of the attribute to sort by.  "" for no sort</param>
        /// <param name="sortAttributes">Sort attributes none, ascending or decending for all sorted XML nodes</param>
        /// <returns>Sorted XElement based on the criteria passed in.</returns>
        private static XElement Sort(XElement element, int level, string attribute, int sortAttributes)
        {
            XElement newElement = new XElement(element.Name,
                from child in element.Elements()
                orderby 
                    (child.Ancestors().Count() > level) 
                        ? ( 
                            (child.HasAttributes && !string.IsNullOrEmpty(attribute) && child.Attribute(attribute) != null) 
                                ? child.Attribute(attribute).Value.ToString() 
                                : child.Name.ToString() 
                            ) 
                        : ""  //End of the orderby clause
                select Sort(child, level, attribute, sortAttributes));
            if (element.HasAttributes)
            {
                switch (sortAttributes)
                {
                    case 0: //None
                        foreach (XAttribute attrib in element.Attributes())
                        {
                            newElement.SetAttributeValue(attrib.Name, attrib.Value);
                        }
                        break;
                    case 1: //Ascending
                        foreach (XAttribute attrib in element.Attributes().OrderBy(a => a.Name.ToString()))
                        {
                            newElement.SetAttributeValue(attrib.Name, attrib.Value);
                        }
                        break;
                    case 2: //Decending
                        foreach (XAttribute attrib in element.Attributes().OrderByDescending(a => a.Name.ToString()))
                        {
                            newElement.SetAttributeValue(attrib.Name, attrib.Value);
                        }
                        break;
                    default:
                        break;
                }
            }
            return newElement;
        } 
        #endregion

        #region Event Handler - btnGenerate_Click
        /// <summary>
        /// Click event for the btnGenerate button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnGenerate_Click(object sender, System.EventArgs e)
        {
            if (string.IsNullOrEmpty(txtSource.Text.Trim()))
            {
                MessageBox.Show("Enter a filename!", "File Name Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            if (!txtSource.Text.EndsWith(".xml"))
                sourceDoc = txtSource.Text + ".xml";
            else
                sourceDoc = txtSource.Text;

            try
            {
                txtResult.Clear();

                XDocument sortedDoc = RunSort(sourceDoc, (int)numericUpDown.Value, txtAttribute.Text, comboBox1.SelectedIndex);

                txtResult.Text = sortedDoc.ToString();
            }

            catch (FileNotFoundException filexc)
            {
                MessageBox.Show(string.Format("File Not Found: {0}", filexc), "File Not Found Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }


            catch (Exception exc)
            {
                MessageBox.Show(string.Format("Error: {0}", exc), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        } 
        #endregion

        #region Event Handler - btnReset_Click
        /// <summary>
        /// Click handler for the btnReset button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnReset_Click(object sender, System.EventArgs e)
        {
            txtSource.Text = "";
            txtResult.Text = "";
            numericUpDown.Value = 0;
            txtAttribute.Text = "";
            comboBox1.SelectedIndex = 0;
            txtSource.Focus();
        } 
        #endregion

        #region Event Handler - btnBrowse_Click
        /// <summary>
        /// Click handler for the btnBrowse button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnBrowse_Click(object sender, EventArgs e)
        {
            if (openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                txtSource.Text = openFileDialog.FileName;
            }
        } 
        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Pacific Interpreters
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions