Click here to Skip to main content
11,645,499 members (80,712 online)
Click here to Skip to main content

XML Alphabetizer

, 8 Mar 2011 CPOL 30.3K 2.7K 13
Rate this:
Please Sign up or sign in to vote.
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.

Introduction

This project will allow the user to alphabetize any XML file without having to translate that file using XSLT.

I searched quite a bit for a way to sort an XML document alphabetically and most of the results I got were based on overly complicated XSLT translation. Some of the templates that I was working with to get my XML document sorted worked for some piece of the puzzle, but after spending a lot of time, I decided to start over using Linq and the XDocument.

I ended up creating a solution that will sort any XML document based on the name of the XML node, any attribute of an XML node(s) and based on a particular depth within that XML document. This utility will also sort all attributes of the XML nodes alphabetically ascending or descending from left to right.

Examples

Original XML - Unsorted

<Collection>
   <CollectionB>
      <B2 Text="1" Stat="5"></B2>
      <A2 Text="2" Type="3" Stat="7"></A2>
      <A1></A1>
      <B1 typeName="2">
		  <B22></B22>
		  <A22></A22>
		  <A12></A12>
	  </B1>
      <B1 typeName="1"></B1>
   </CollectionB>
   <CollectionA>
      <B2 Echo="1" Bravo="1" Tango="1" Alpha="1"></B2>
      <A2></A2>
      <A1></A1>
      <B1></B1>
   </CollectionA>
</Collection>

Default Sort

<Collection>
  <CollectionA>
    <A1 />
    <A2 />
    <B1 />
    <B2 Echo="1" Bravo="1" Tango="1" Alpha="1" />
  </CollectionA>
  <CollectionB>
    <A1 />
    <A2 Text="2" Type="3" Stat="7" />
    <B1 typeName="2">
      <A12 />
      <A22 />
      <B22 />
    </B1>
    <B1 typeName="1" />
    <B2 Text="1" Stat="5" />
  </CollectionB>
</Collection>

Sort by "Text" Attribute

<Collection>
  <CollectionA>
    <A1 />
    <A2 />
    <B1 />
    <B2 Echo="1" Bravo="1" Tango="1" Alpha="1" />
  </CollectionA>
  <CollectionB>
    <B2 Text="1" Stat="5" />
    <A2 Text="2" Type="3" Stat="7" />
    <A1 />
    <B1 typeName="2">
      <A12 />
      <A22 />
      <B22 />
    </B1>
    <B1 typeName="1" />
  </CollectionB>
</Collection>

Sort by "Text" Attribute below level 2 within XML Tree

<Collection>
  <CollectionB>
    <B2 Text="1" Stat="5" />
    <A2 Text="2" Type="3" Stat="7" />
    <A1 />
    <B1 typeName="2">
      <A12 />
      <A22 />
      <B22 />
    </B1>
    <B1 typeName="1" />
  </CollectionB>
  <CollectionA>
    <B2 Echo="1" Bravo="1" Tango="1" Alpha="1" />
    <A2 />
    <A1 />
    <B1 />
  </CollectionA>
</Collection>

Default Sort - Sort Attributes Ascending

<Collection>
  <CollectionB>
    <B2 Stat="5" Text="1" />
    <A2 Stat="7" Text="2" Type="3" />
    <A1 />
    <B1 typeName="2">
      <A12 />
      <A22 />
      <B22 />
    </B1>
    <B1 typeName="1" />
  </CollectionB>
  <CollectionA>
    <B2 Alpha="1" Bravo="1" Echo="1" Tango="1" />
    <A2 />
    <A1 />
    <B1 />
  </CollectionA>
</Collection>

Background

Lambda Expressions

I rely heavily on Lambda expressions within this code to cut down on the lines of code and to utilize Linq in the most efficient way. More concise code can be achieved by using Lambda expressions instead of delegates. Here is a quick example of a Lambda expression to give you some background into the syntax before we dive into the code.

For this example, let's take a strongly typed collection of Customer objects.

List<Customer> myCustomers;

A Customer has a public property FirstName.
Once this collection is filled with Customer objects, we can then sort that collection based on each Customer.FirstName.

list = list.OrderBy(x => x.FirstName).toList(); --Sort ascending
list = list.OrderByDescending(x => x.FirstName).toList(); --Sort descending

In the syntax above, the "x" represents a Customer object. You can use any variable name you choose.

Hint: When you are typing a Lambda expression and you get to the part of the syntax where you type the "." after "x", you should get code completion and be able to choose from any visible property of that object.

Conditional Operator

Conditional Operator within that orderby clause. I could find no other supported way to perform an inline sort and apply logic at the same time. In this example, I am using a two level conditional statement to verify that the current child node has children below the chosen level and to verify that the current child node has valid attributes; If these conditions are met, then sort by the value of the attribute that has the name we specified in the UI.

This operator is very useful when trying to assign a variable to another variable only if a certain condition is true and if not, then assign it to another value. The operator uses ? and : and is basically (if true) ? then : else.

Normal "if" syntax:

if (myValue == "something")
{
	otherValue = myValue;
}
else
{
	otherValue = "defaultValue";
}

Simplified syntax using the Conditional Operator:

otherValue = (myValue == "something") ? myValue : "defaultValue";

Using the Utility

In this example (Figure 1), I am loading the XML file "Test.xml", starting my sort at node level 2, sorting by the attribute "Text" and sorting all XML attributes alphabetically in ascending order left to right.

All results are saved to a file called "result.xml" in the working directory (overwrite) each run as well as shown in the TextArea at the bottom of the form window.

XML Alphabetizer

Figure 1

Note: If a full path is not specified for the Source XML file, I look in the working directory and append ".xml" to the file name if not present.

Using the Code

The core of this utility utilizes the XDocument Linq object to load all of the XML, manipulate it, then spit it out in the order requested.

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);
}

To perform the sort on the XML tree, we use Linq to query the collection of XML objects, apply an "orderby" clause based on the options that were selected from the UI, then recursively call the Sort method for all the nodes found.

If we choose to sort the attributes of all XML nodes, then we will enter into the switch statement and apply a sort to the collection of XAttribute objects associated with that particular XML node.

#region Private Method - Sort
/// <span class="code-SummaryComment"><summary>
</span>

Points of Interest

This is the first time that I have the need to use a Linq query and after finding a good example online, I was able to use it to successfully iterate through the entire collection, perform an orderby on the objects, then perform an action based on each item returned.

One thing that I learned is that if you need to add some logic within an orderby clause of a Linq query, you must use a:

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));

History

  • Version 1.0 - Original submission

License

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

Share

About the Author

Matt Heidenreich
Software Developer (Senior) Pacific Interpreters
United States United States
No Biography provided

You may also be interested in...

Comments and Discussions

 
QuestionHow to retain the innerText in xml element after sorting. Pin
Member 1170466720-May-15 0:39
memberMember 1170466720-May-15 0:39 
AnswerRe: How to retain the innerText in xml element after sorting. Pin
Member 1170466720-May-15 1:21
memberMember 1170466720-May-15 1:21 
GeneralMy vote of 5 Pin
philippdev1-Jan-15 0:25
memberphilippdev1-Jan-15 0:25 
QuestionBrilliant Pin
Member 1132831922-Dec-14 20:51
memberMember 1132831922-Dec-14 20:51 
QuestionHow do i launch the app??? Pin
Member 1089728120-Jun-14 14:15
memberMember 1089728120-Jun-14 14:15 
GeneralVery useful Pin
Carl Reid20-Mar-14 0:47
memberCarl Reid20-Mar-14 0:47 
Questioncompiled version ? Pin
Member 1060662418-Feb-14 7:32
memberMember 1060662418-Feb-14 7:32 
QuestionJust what I was looking for Pin
iuerghiaujvgf3-Aug-12 5:37
memberiuerghiaujvgf3-Aug-12 5:37 
AnswerRe: Just what I was looking for Pin
Kochise9-Jan-14 22:46
memberKochise9-Jan-14 22:46 
QuestionFanastic! Pin
Mr. Friendly3-Sep-11 3:30
memberMr. Friendly3-Sep-11 3:30 
GeneralMy vote of 5 Pin
Mr. Friendly3-Sep-11 3:28
memberMr. Friendly3-Sep-11 3:28 
GeneralMy vote of 5 Pin
Shannon McCoy24-Aug-11 9:26
memberShannon McCoy24-Aug-11 9:26 
GeneralError when sorting elements containing text Pin
Paul M Griffin25-May-11 5:14
memberPaul M Griffin25-May-11 5:14 
If you add some test text data to the elements the sorted output omits the text data.
GeneralRe: Error when sorting elements containing text Pin
James Brinkerhoff7-Feb-12 10:35
memberJames Brinkerhoff7-Feb-12 10:35 
Generalxslt does not seem overly complicated Pin
moozzyk16-Mar-11 20:22
membermoozzyk16-Mar-11 20:22 
GeneralMy vote of 4 Pin
John Brett8-Mar-11 21:19
memberJohn Brett8-Mar-11 21:19 
QuestionWhy did you need this? Pin
JV99998-Mar-11 21:06
memberJV99998-Mar-11 21:06 
AnswerRe: Why did you need this? Pin
f50bodyjunk15-Mar-11 10:17
memberf50bodyjunk15-Mar-11 10:17 
GeneralRe: Why did you need this? Pin
JV999922-Mar-11 0:07
memberJV999922-Mar-11 0:07 
AnswerRe: Why did you need this? Pin
Matt Heidenreich30-Apr-12 11:25
memberMatt Heidenreich30-Apr-12 11:25 
AnswerRe: Why did you need this? Pin
John W Washburn14-Mar-13 1:30
memberJohn W Washburn14-Mar-13 1:30 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.150731.1 | Last Updated 8 Mar 2011
Article Copyright 2011 by Matt Heidenreich
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid