Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ Timesaving Techniques (2005) [eng].pdf
Скачиваний:
65
Добавлен:
16.08.2013
Размер:
8.35 Mб
Скачать

Testing the XML Writer 243

void setFileName( const char *fileName )

{

_out.open(fileName);

if ( _out.fail() == false )

{

_out << “<xml>” << endl;

}

}

virtual bool Write( XMLElement& aRoot )

{

if ( _out.fail() ) return false;

// First, process the element. _out << “<” <<

aRoot.getName().c_str() << “>” << endl;

//If there is a value, output it. if ( aRoot.getValue().length()

!= 0 )

_out << aRoot.getValue().c_str()

<<endl;

//Now, process all sub-elements. for ( int i=0;

i<aRoot.numSubElements(); ++i )

Write( aRoot.getSubElement(i) );

// Finally, close the element. _out << “</” <<

aRoot.getName().c_str() << “>” << endl;

}

};

This listing illustrates the basics of our XML writing functionality. Each element of an XML object will be stored in an XMLElement object. The writer (XMLWriter class) then processes each of these elements to output them in valid XML format.

3. Save the source-code file and close your editor application.

4. Compile the application with your favorite compiler, on your favorite operating system, to verify that you have made no errors.

Testing the XML Writer

After you create the class, you should create a test driver that not only ensures that your code is correct, but also shows people how to use your code.

The following steps show you how to create a test driver that illustrates various types of data elements, and will illustrate how the class is intended to be used.

1. In the code editor of your choice, reopen the source file for your test program.

In this example, I named the test program ch43.cpp.

2. Type the code from Listing 43-2 into your file.

Better yet, copy the code from the source file on this book’s companion Web site.

LISTING 43-2: THE XMLWRITER TEST CODE

class XmlTest

{

private:

int iVal; string sVal; double dVal;

public:

XmlTest()

{

iVal = 100; sVal = “Test”; dVal = 123.45;

}

~XmlTest()

{

}

XMLElement getXML(void)

{

XMLElement e(“XmlTest”, “”); e.addSubElement(

XMLElement(“iVal”, iVal) ); e.addSubElement(

XMLElement(“sVal”, sVal. c_str()) );

e.addSubElement( XMLElement(“dVal”, dVal) );

return e;

(continued)

244 Technique 43: Writing Your Objects as XML

LISTING 43-2 (continued)

}

};

 

 

 

class XmlSuperClass

 

1

{

 

2

XmlTest

xt;

 

int

count;

 

public:

XmlSuperClass()

{

count = 1;

}

~XmlSuperClass()

{

}

XMLElement getXML()

{

// First, do ourselves

XMLElement e(“XmlSuperClass”, “”); e.addSubElement(

XMLElement(“count”, count) );

// Now the sub-object e.addSubElement( xt.getXML() );

return e;

}

};

void TestWriter1(void)

{

XMLElement ele1(“Sub-Element1”, “123”); XMLElement ele2(“Sub-Element2”, “234”); XMLElement subele1(“Sub-Sub-Element1”, “345”);

XMLElement subele2(“Sub-Sub-Element2”, “456”);

XMLElement root(“Root”, “”);

ele1.addSubElement( subele1 ); ele2.addSubElement( subele2 ); root.addSubElement( ele1 ); root.addSubElement( ele2 );

XMLWriter writer(“test.xml”); writer.Write( root );

}

void TestWriter2(void)

{

XmlSuperClass xsc;

XMLWriter writer(“test2.xml”); XMLElement e = xsc.getXML(); writer.Write( e );

}

int main()

{

TestWriter1();

TestWriter2(); return 0;

}

3. Save the source-code file and close the editor application.

4. Compile the application, using your favorite compiler on your favorite operating system.

If you have done everything properly, running the application results in the creation of two files, test.xml and test2.xml. If you look at the contents of these files, you should see the following:

test.xml:

$ cat test.xml <xml>

<Root> <Sub-Element1> 123 <Sub-Sub-Element1> 345

</Sub-Sub-Element1> </Sub-Element1> <Sub-Element2>

234 <Sub-Sub-Element2> 456 </Sub-Sub-Element2> </Sub-Element2> </Root>

</xml>

Testing the XML Writer 245

test2.xml:

$ cat test2.xml <xml> <XmlSuperClass> <count>

1

</count>

<XmlTest>

<iVal>

100

</iVal>

<sVal> Test </sVal> <dVal> 123.450000 </dVal> </XmlTest>

</XmlSuperClass>

</xml>

3

4

5

If we look at the class hierarchy shown in the application source code, we see that the main class,

XmlSuperClass (shown at

 

1), contains both stan-

 

 

 

 

 

 

 

dard data elements (count, an integer) and embed-

ded objects (XmlTest, shown at

 

2). In the XML

output, we see these elements

at the lines marked

 

 

 

 

 

3 and 4. Note how the embedded class con-

tains its own elements (shown at 5

in the output

 

 

 

 

 

 

 

list) which are children of both

the

 

XmlTest and

XmlSuperClass classes.

The code shows that both cases work fine — the simple case of using the XMLElement and XMLWriter classes, and the embedded case of outputting an entire C++ class with an embedded C++ object.

44 Removing White

Space from Input

Technique

Save Time By

Stripping leading and trailing spaces from input

Returning the modified string back to your application

Testing your code

Although it might not seem like a big deal, dealing with white space in input from either files or the console can be a major pain in the neck for C++ programmers. After all, white space isn’t empty; it

has to be accounted for. When you want to store a user name in your database, for example, do you really want to store any leading and trailing spaces, tabs, or other non-printing characters? If you do so, the users will then have to remember to type those spaces in again whenever they log in to your application. While this might be a useful security condition, it seems unlikely that anyone would remember to add either leading or trailing spaces to a user name or password in an application.

For this reason, if you give your code the capability to strip off leading and trailing spaces from a given string with no fuss — and return that string to the calling application — you save a lot of time and hassle. This technique looks at creating that exact capability. The following steps show you how:

1. In the code editor of your choice, create a new file to hold the code for the implementation of the source file.

In this example, the file is named ch44.cpp, although you can use whatever you choose.

2. Type the code from Listing 44-1 into your file.

Better yet, copy the code from the source file on this book’s companion Web site.

LISTING 44-1: THE WHITE SPACE REMOVAL CODE

#include <string> #include <ctype.h>

//Nobody wants to have to type std:: for

//all of the STL functions.

using namespace std;

Removing White Space from Input 247

string strip_leading( const string& sIn )

{

string sOut;

//Skip over all leading spaces. unsigned int nPos = 0;

while ( nPos < sIn.length() )

{

if ( !isspace(sIn[nPos]) ) break;

nPos ++;

}

//Now we have the starting position of

//the “real” string. Copy to the end...

while ( nPos < sIn.length() )

{

sOut += sIn[nPos]; nPos ++;

}

//...and give back the new string,

//without modifying the input string. return sOut;

}

string strip_trailing( const string& sIn )

{

string sOut;

1

//Skip over all trailing spaces. int nPos = sIn.length()-1;

while ( nPos >= 0 )

{

if ( !isspace(sIn[nPos]) ) break;

nPos --;

}

//Now we have the ending position of

//the “real” string. Copy from the

//beginning to that position...

for ( int i=0; i<=nPos; ++i ) sOut += sIn[i];

//...and give back the new string,

//without modifying the input string. return sOut;

}

int main(int argc, char **argv )

{

if ( argc > 2 )

{

printf(“Removing Leading Spaces\n”); for ( int i = 1; i < argc; ++i )

{

printf(“Input String: [%s]\n”, argv[i] );

string s = argv[i];

s = strip_leading( s ); printf(“Result String: [%s]\n”,

s.c_str() );

}

printf(“Removing Trailing Spaces\n”);

for ( int i = 1; i < argc; ++i )

{

printf(“Input String: [%s]\n”, argv[i] );

string s = argv[i];

s = strip_trailing( s ); printf(“Result String: [%s]\n”,

s.c_str() );

}

printf(“Removing both leading and trailing\n”);

for ( int i = 1; i < argc; ++i )

{

printf(“Input String: [%s]\n”, argv[i] );

string s = argv[i];

s = strip_trailing( strip_ leading(s) );

printf(“Result String: [%s]\n”, s.c_str() );

}

}

else

{

(continued)

248 Technique 44: Removing White Space from Input

LISTING 44-1 (continued)

bool bDone = false; while ( !bDone )

{

char szBuffer[ 80 ]; printf(“Enter string to fix: “); gets(szBuffer);

printf(“Input string: [%s]\n”, szBuffer );

//Strip the trailing carriage return.

if ( strlen(szBuffer) ) szBuffer[strlen(szBuffer)-1] = 0;

if ( !strlen(szBuffer) ) bDone = true;

else

{

string s = szBuffer;

s = strip_leading( s ); printf(“After removing leading: %s\n”, s.c_str() ); s = strip_trailing( s ); printf(“After removing trailing: %s\n”, s.c_str() );

}

}

}

return 0;

}

Stripping any trailing white space from a string is a simple endeavor. You just find the last white space character and truncate the string at that point. Stripping leading white space, on the other hand, is a more complicated problem. As you can see at the line marked 1 in the source listing, you must create a separate string to use for the return value of the strip_leading function. This string is then built-up by finding the first nonblank character in the input string and then copying everything from that point to the end of the string into the output string. The output string is then returned to the calling application sans leading white space.

3. Save the source-code file and close the editor application.

4. Compile the application with your favorite compiler on your favorite operating system.

If you have done everything properly, and you run the program with the following command-line options, you should see the following output in your console window:

$ ./a “ this is a test

 

“ “ hello

 

goodbye”

 

 

 

 

 

 

Removing Leading Spaces

 

 

 

 

2

Input String: [

this is

a test

]

 

Result String: [this is a

test ]

 

3

Input String: [ hello

]

 

 

 

 

Result String: [hello

]

 

 

 

 

Input String: [

goodbye]

 

 

 

Result String: [goodbye]

 

 

 

 

 

Removing Trailing Spaces

 

 

 

 

 

Input String: [

this is

a test

]

 

4

Result String: [

this is a test]

 

 

Input String: [ hello

]

 

 

 

Result String: [ hello]

 

 

 

 

 

Input String: [

goodbye]

 

 

 

Result String: [

goodbye]

 

 

 

Removing both leading and

trailing

 

 

 

Input String: [

this is

a test

]

 

5

Result String: [this is a

test]

 

 

Input String: [ hello

]

 

 

 

Result String: [hello]

 

 

 

 

 

Input String: [

goodbye]

 

 

 

Result String: [goodbye]

In the output, we see that each string is input into the system, then the various white space characters in the front and back of the string are removed. In each case, the string is output to the user to view how it is modified. For example, if we look at the input line at 2, we see that it contains both leading and trailing spaces. When the strip_leading function is applied, we get the result shown at 3, which is the same string with no leading spaces. When the strip_trailing function is applied, we get the result shown at 4, which is the same string with no trailing spaces. Finally, we apply both of the

Removing White Space from Input 249

functions at the same time, and get the result shown at 5, which has neither leading nor trailing spaces.

You can also test the application by typing in data from the prompt by running the application with no input arguments. Here is a sample of what the test looks like in that form:

$ ./a.exe

Enter string to fix: this is a test Input string: [ this is a test ] After removing leading: this is a test After removing trailing: this is a test Enter string to fix:

Input string: []

As you can see, input from either the command line or from user entries (whether from the keyboard or a file) can contain white space. This white space must be removed to look at the “real” strings in many cases, and these functions will save you a lot of time by doing it for you automatically.

45 Creating a

Configuration File

Technique

Save Time By

Creating a standard interface to a configuration file

Creating the configuration-file class

Creating the test input file

Testing the configurationfile class

Configuration files are a basic part of any application that needs to be portable across various operating systems. Because of differences in binary formats and “endian” concerns (placement of the

most significant byte), configuration files are normally stored in text format. This is somewhat problematic, as it requires the application to be able to load, parse, and work with the entries in a configuration file, while interpreting the data that is stored there. Because the format is text, you must worry about the user modifying the text files, changing them so that they are no longer in a valid format, and the like. It would make sense, therefore, if there were a standard interface to a configuration file, and a standard format for using text-based configuration files. This would allow you to use a standard format in all of your applications, saving you time and effort.

This technique shows you how to develop a method for storing data in the simplest possible fashion in a configuration file (text based), while still allowing the users to store the kinds of data they need. A typical entry in one of our configuration files would look like this:

# This is a comment

Value = “ This is a test”

The first line of the entry is a comment field — ignored by the parser — that tells any reader of the configuration file why the specific data is stored in this key (and how it might be interpreted or modified). The second line is the value itself, which is made up of two pieces:

The keyword that we are defining, in this case Value.

The complete string assigned to this value, with embedded and possi-

bly leading spaces. In this case, our value string is “ This is a test”. Note that when read in, the string will contain leading spaces, as the user wished. Note that the only reason that we store these spaces is that they are contained in quotation marks, indicating the user wished to keep them. If the spaces were simply on the leading and trailing edges of strings in the entry without quotation marks, we would remove them.