|
The first step in creating the middle tier example is creating the class needed to access the XML data. The example in this chapter utilizes a SAX-like parser to read the data as events. This provides a less efficient means of reading data, but provides fast access to the information. Even though this chapter examines accessing just one XML file, you could abstract access to several different files if you needed to.
The following XML data contains all the information needed for the three users allowed to access a particular Web site. Accessing data from XML will be faster than calling a RDBMS as long as you only have a few hundred or thousand records to access.
Notice that the root element is users and then the user parent tag represents each individual’s data. The order of the elements usually doesn’t matter for XML, but for the program shown later in the chapter the order does matter when it searches via the ID element. Remember that Chapter 2 provided a quick introduction to XML. You may want to refer to that chapter if the following XML doesn’t make sense to you.
<?xml version='1.0'?> <!-- This file represents a fragment of a book store inventory database --> <users> <user> <id>101111</id> <password>hellodollie</password> <email>brianhochgurtel@hotmail.com</email> <title>Senior Programmer</title> <first-name>Brian</first-name> <last-name>Hochgurtel</last-name> </user> <user> <id>10112</id> <password>something</password> <email>secret@hotmail.com</email> <title>Senior Programmer</title> <first-name>David</first-name> <last-name>Pallai</last-name> </user> <user> <id>101113</id> <password>forever</password> <email>JohnDoe@hotmail.com</email> <title>Master Programmer</title> <first-name>John</first-name> <last-name>Doe</last-name> </user> </users>
This XML contains three different users, each with unique IDs and passwords. This makes it easy to use this information to restrict access to a Web site.
The following C# code sample uses the XmlTextReader class to grab data from the XML shown in the previous section. Because the data in this file is element centric, the only node you need to worry about in this case is XMLNoteType.Text. This provides you with the data that appears between the opening and closing tags.
The first step in this code defines which XML file to parse. In this example, the name of the file resides in a static string, but later examples actually provide a method to change the name and location of the XML file.
Then the SearchStringXml method defines a routine for searching the document for one particular string. You pass in a string, the document is parsed, and each value that appears between the elements is compared to the string passed in. If there is a match, 0 returns; otherwise, the return value will be 1.
This return value is the opposite of what you’d normally expect. A 1 should return for a condition that is true, but the string.Compare method returns 0. This is something you should pay close attention to because it may cause some unexpected logic to occur in your code.
The next method, getData, still parses only for the content of the elements, but now it does a search for the element you pass in. This code is set up to search by the value of the ID element. If you search on another element, the hash this class contains will return unexpected values. There are other parsing methods, such as DOM, that allow you to ask a parser for a particular element, but they are very memory intensive and will add time to accessing your data. This method of parsing the document is very fast but more inflexible.
Once the loop that searches for a match is true, a counter that keeps track of the number of elements is incremented each time. This allows the code to determine in which element to put the appropriate hash key. The count simply tracks which number of element you are on. For example, element Number 1 is ID, Number 2 contains the password, and Number 3 possesses the e-mail address. This count goes all the way up to 6 because there are 6 elements. This is why the order of the elements is so important in this case. If you move the elements around, the values end up with the incorrect hash key.
The main method then provides a means of testing the code you just created. The first call to the SearchStringXml method determines that the ID 101111 does exist within the XML. Then the call to the getData method puts all the appropriate personal information into the hash for the user with ID 101113.
using System; using System.IO; using System.Xml; using System.Collections; namespace XMLTester { class GetXml { private static string myDocument = "users.xml"; private int SearchStringXml (String searchString) { int returnFlag = 0; XmlTextReader reader = new XmlTextReader (myDocument); while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Text: returnFlag = string.Compare(reader.Value,searchString); if (returnFlag == 1) return(1); break; } } return(0); } private Hashtable getData(String searchString) { XmlTextReader reader = new XmlTextReader (myDocument); int returnFlag = 0; int elementCount =0; Hashtable myHashTable = new Hashtable(); while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Text: returnFlag =string.Compare (reader.Value,searchString); Console.WriteLine ("Debug:" + returnFlag + reader.Value + searchString); if (returnFlag == 0) elementCount++; if (elementCount >0 && elementCount <= 6) { if(elementCount == 1) { myHashTable.Add("id",reader.Value); elementCount++; Console.WriteLine ("Debug:" + reader.Value + elementCount); } else if(elementCount == 2) { myHashTable.Add("password",reader.Value); elementCount++; Console.WriteLine ("Debug:" + reader.Value + elementCount); } else if (elementCount == 3) { myHashTable.Add ("email",reader.Value); elementCount++; Console.WriteLine ("Debug:" + reader.Value + elementCount); } else if (elementCount == 4) { myHashTable.Add("title",reader.Value); elementCount++; Console.WriteLine ("Debug:" + reader.Value + elementCount); } else if (elementCount == 5) { myHashTable.Add ("FirstName",reader.Value); elementCount++; Console.WriteLine ("Debug:" + reader.Value + elementCount); } else if (elementCount == 6) { myHashTable.Add("LastName",reader.Value); elementCount++; Console.WriteLine ("Debug:" + reader.Value + elementCount); } } break; } } return(myHashTable); } [STAThread] static void Main(string[] args) { GetXml myGetXml = new GetXml(); try { // Load the file with an XmlTextReader int results = myGetXml.SearchStringXml("101111"); Hashtable myHashTable = new Hashtable(); myHashTable = myGetXml.getData("101113"); Console.WriteLine ("Franklin was written:" + results); Console.WriteLine ("ID:" + myHashTable["id"]); Console.WriteLine ("email:" + myHashTable["email"]); Console.WriteLine ("title:" + myHashTable["title"]); Console.WriteLine ("firstname:" + myHashTable["FirstName"]); Console.WriteLine ("lastname:" + myHashTable["LastName"]); } catch (Exception e) { Console.WriteLine ("Exception: {0}", e.ToString()); } } } }
Now that you know that the code works for the purposes of accessing XML data, the following code example takes the previous program and turns the code into a dll. This is completed by taking the code and removing the main, and then creating a project for a C# class library, as shown in Figure 12.2. This creates a dll that the Web Service example imports into its namespace.
Figure 12.2: Creating a C# class library in Visual Studio.NET.
Note | If you only have access to Microsoft’s .NET SDK, you can compile the following code example into a dll using the command line C# compiler with the following command csc /t:library. You also need to include any namespaces or other dlls needed for your library. Chapter 6 went into greater detail of using the command line compiler. |
Once you have your new project open, just paste in the following code and compile it. This creates a dll in your project directory that the Web Service application needs in order to call this XML parsing code.
using System; using System.IO; using System.Xml; using System.Collections; namespace XmlSearchString { class GetXmlLibrary { private string myDocument = "users.xml"; public void setDocumentPath(string docPath) { myDocument = docPath; } public int SearchStringXml (String searchString) { int returnFlag = 0; XmlTextReader reader = new XmlTextReader (myDocument); while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Text: returnFlag = string.Compare(reader.Value,searchString); if (returnFlag == 1) return(1); break; } } return(0); } public Hashtable getData(String searchString) { XmlTextReader reader = new XmlTextReader (myDocument); int returnFlag = 0; int elementCount =0; Hashtable myHashTable = new Hashtable(); while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Text: returnFlag = string.Compare(reader.Value,searchString); if (returnFlag == 0) elementCount++; if (elementCount >0 && elementCount <= 6) { if(elementCount == 1) { myHashTable.Add("id",reader.Value); elementCount++; } else if(elementCount == 2) { myHashTable.Add("password",reader.Value); elementCount++; } else if (elementCount == 3) { myHashTable.Add ("email",reader.Value); elementCount++;} } else if (elementCount == 4) { myHashTable.Add("title",reader.Value); elementCount++; } else if (elementCount == 5) { myHashTable.Add("FirstName",reader.Value); elementCount++; } else if (elementCount == 6) { myHashTable.Add("LastName",reader.Value); elementCount++; } } break; } } return(myHashTable); } } }
Once you are ready to deploy your dll, you should create a production build. This is done from the “Build” menu. Select “Build” and then “Configuration Manager” and you will see what appears in Figure 12.3.
Figure 12.3: The “Build” settings for the XML parsing code.
On the “Configuration” drop-down box, select “Release.” This removes all the debug symbols from your dll and makes the code execute faster.
|