
APPENDIX A Creating a Custom XmlReader and XmlWriter In Chapter 3, you learned about the XmlReader and XmlWriter classes. The abstract classes XmlReader and XmlWriter can be used in three ways: • To call the Create() method of the respective classes that return an instance of the generic XmlReader or XmlWriter classes • To use the concrete classes XmlTextReader and XmlTextWriter provided by the .NET Framework • To create custom classes that inherit from the XmlReader and XmlWriter classes You are already familiar with the first two approaches. In the following sections, you are going to learn how to create custom readers and writers from the abstract base classes XmlReader and XmlWriter. Creating a Custom XmlReader In this section, you will create a custom implementation of the XmlReader class. The SqlCommand class provides the ExecuteXmlReader() method that returns an instance of XmlReader to the caller. This works fine if your database is SQL Server, but what if your database is Microsoft Office Access or any other OLEDB- compliant database? Moreover, XML extensions such as the FOR XML clause may not be available for all databases. Does that mean that you cannot retrieve the data and read it by using an XmlReader? Of course not. There is no out-of-the-box solution for this problem, but you can build your own mechanism to overcome this limitation, by creating a custom class that inherits from the XmlReader abstract class. You can then override the required properties and methods as per your need. The requirements for the custom XmlReader class are summarized here: • It should accept the database connection string and table name to read. • The column values should be treated as attribute values. • It should allow iterating through the table to read each row. • The column values should be accessible by specifying a column index or name. © Bipin Joshi 2017 421 B. Joshi, Beginning XML with C# 7, https://doi.org/10.1007/978-1-4842-3105-0 APPENDIX A ■ CREaTING a CUSTOM XMLREaDER aND XMLWRITER Inheriting from XmlReader The XmlReader class is an abstract class and provides several properties and methods that you need to override when you inherit from it. Listing A-1 shows signatures of these properties and methods. Listing A-1. Properties and Methods of the XmlReader Class public abstract int AttributeCount; public abstract string BaseURI { get; } public abstract void Close(); public abstract int Depth { get; } public abstract bool EOF { get; } public abstract string GetAttribute(int i); public abstract string GetAttribute(string name, string namespaceURI); public abstract string GetAttribute(string name); public abstract bool HasValue { get; } public abstract bool IsEmptyElement { get; } public abstract string LocalName { get; } public abstract string LookupNamespace(string prefix); public abstract bool MoveToAttribute(string name, string ns); public abstract bool MoveToAttribute(string name); public abstract bool MoveToElement(); public abstract bool MoveToFirstAttribute(); public abstract bool MoveToNextAttribute(); public abstract XmlNameTable NameTable { get; } public abstract string NamespaceURI { get; } 422 APPENDIX A ■ CREaTING a CUSTOM XMLREaDER aND XMLWRITER public abstract XmlNodeType NodeType { get; } public abstract string Prefix { get; } public abstract bool Read(); public abstract bool ReadAttributeValue(); public abstract ReadState ReadState { get; } public abstract void ResolveEntity(); public abstract string Value { get; } You can override these properties and methods and write your own data-manipulation logic. If you do not want to override a particular property or method, you still need to have its empty implementation. A better way is to throw an exception in such properties and methods so that the caller knows that these properties and methods are not implemented by you. I will not discuss every property here because you are already familiar with many of them (see Chapter 3 for more information). Creating the TableReader Class Now that you are familiar with the XmlReader abstract class, let’s create our own implementation. To do so, create a new project of type class library by using Visual Studio. Add a class named TableReader. Make sure that references to the System.Xml and System.Data assemblies are added to the project. Import the namespaces as shown in Listing A-2 at the top of the TableReader class and ensure that the TableReader class inherits from the XmlReader class. Listing A-2. Importing Namespaces and Setting Inheritance using System.Xml; using System.Data; using System.Data.OleDb; class TableReader:XmlReader { ... You need to add an implementation of each property and method mentioned. Visual Studio provides a shortcut for adding empty implementations of these members. Go to the class declaration line and look for the Quick Actions icon in the left margin. Open the Quick Actions list and choose the Implement Abstract Class option (see Figure A-1). 423 APPENDIX A ■ CREaTING a CUSTOM XMLREaDER aND XMLWRITER Figure A-1. Adding empty implementations of properties and methods This will add dummy signatures of all the properties and methods that need to be overridden. Notice how the dummy implementation throws an exception by using the throw keyword. This way, if somebody tries to use unimplemented members, an exception will be thrown indicating that “the method or operation is not implemented.” Code the TableReader class as shown in Listing A-3. Listing A-3. The TableReader Class public class TableReader:XmlReader { private OleDbConnection cnn; private OleDbCommand cmd; private OleDbDataReader reader; private int intColumnIndex = -1; private string strValue; public TableReader(string connectionString,string tableName) { cnn = new OleDbConnection(connectionString); cmd = new OleDbCommand(); cmd.Connection = cnn; cmd.CommandText = tableName; cmd.CommandType = CommandType.TableDirect; cnn.Open(); reader = cmd.ExecuteReader(); } public override int AttributeCount { get { return reader.FieldCount; } } public override void Close() { reader.Close(); cnn.Close(); } 424 APPENDIX A ■ CREaTING a CUSTOM XMLREaDER aND XMLWRITER public override int Depth { get { return reader.Depth; } } public override string GetAttribute(int i) { return reader.GetValue(i).ToString(); } public override string GetAttribute(string name) { return reader.GetValue(reader.GetOrdinal(name)).ToString(); } public override bool MoveToAttribute(string name) { intColumnIndex = reader.GetOrdinal(name); return true; } public override bool MoveToElement() { intColumnIndex = -1; return true; } public override bool MoveToFirstAttribute() { intColumnIndex = 0; return true; } public override bool MoveToNextAttribute() { intColumnIndex++; if (intColumnIndex > reader.FieldCount - 1) { return false; } else { return true; } } 425 APPENDIX A ■ CREaTING a CUSTOM XMLREaDER aND XMLWRITER public override bool Read() { intColumnIndex = -1; strValue = ""; return reader.Read(); } public override bool HasValue { get { return reader.IsDBNull(intColumnIndex); } } public override bool ReadAttributeValue() { if (intColumnIndex < reader.FieldCount) { strValue = reader.GetValue(intColumnIndex).ToString(); return true; } else { return false; } } public string Name { get { if (intColumnIndex == -1) { return cmd.CommandText; } else { return reader.GetName(intColumnIndex); } } } public override string Value { get { return strValue; } } ... } In the following text, we dissect the code step by step. 426 APPENDIX A ■ CREaTING a CUSTOM XMLREaDER aND XMLWRITER Declaring Class-Level Variables private OleDbConnection cnn; private OleDbCommand cmd; private OleDbDataReader reader; private int intColumnIndex = -1; private string strValue; The TableReader class declares private variables of type OleDbConnection, OleDbCommand, and OleDbDataReader at the class level: • The OleDbConnection class is used to establish a connection with any OLEDB- compliant databases. • The OleDbCommand class is used to execute any query, SQL query, or stored procedures against a database. • The OleDbDataReader class allows you to iterate through a result set in a cursor- oriented manner. The intColumnIndex integer variable keeps track of the current column index whose value is to be read. Similarly, the strValue string variable stores the value from the column indicated by intColumnIndex. Initializing the Variables public TableReader(string connectionString,string tableName) { cnn = new OleDbConnection(connectionString); cmd = new OleDbCommand(); cmd.Connection = cnn; cmd.CommandText = tableName; cmd.CommandType = CommandType.TableDirect; cnn.Open(); reader = cmd.ExecuteReader(); } The constructor of the TableReader class accepts two parameters: the database connection string and the name of the table whose data is to be read. Using the connection string, the OleDbConnection is instantiated. The Connection property of the OleDbCommand class is set to the OleDbConnection class we just instantiated. The CommandText property of the OleDbCommand class is set to the name of the table whose data is to be read. Have a look at the CommandType property. It is set to TableDirect, which returns all the rows from the table indicated by the CommandText property. In effect, it works as if we have specified SELECT * FROM <tableName> as the query. The database connection is then opened. The ExecuteReader() method of OleDbCommand is called and an OleDbDataReader is retrieved. 427 APPENDIX A ■ CREaTING a CUSTOM XMLREaDER aND XMLWRITER Retrieving the Total Number of Attributes public override int AttributeCount { get
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages33 Page
-
File Size-