next_inactive up previous


CASL: XML API: Programming Guide
DocumentId:GradSof-CASL-XML-e-PG-26.12.2001-1.0.0

Introduction

One of standard CASLservices is XML API service. Applying the service application programmer may use XML parsing and processing functionality in his applications.

XML API consists of:

Main concepts

What is streaming (or event-driven) parser: is the module, that reads XML elements and generates events (i.e. calls according parser client functions) while reading XML stream.

Considering this we can define corresponding data structures.

Classes

Very high-level presentation gives next classes diagram: png

Exact API description is given in API guide, this document is additional.

XMLTransformer

At last XMLTransformer is the main part of the development. As you can see from UML diagram, XMLTransformer converts input XML events stream to output stream.

XMLTransformer entry is set setXMLSource(XMLSource* src,bool srcOwnity) method,

For each XML event Xxx virual processXxx method is defined , with common parameters set.

Let's consider XML processing algorithm: for each event the corresponding transformer function is called. If the function returns true event is delegated to receiver, otherwise is skipped.

Client overloads in its class, that is inherited from XMLTramsformer, corresponding processing functions processXxx. In the processing functions it can use sendXXX notificator methods , for further messages communication (to final receiver).

Since XMLTransformer implements XMLSource and XMLDostination interfaces, we can build converters chains, as in the following interaction diagram:

XML_Events.png

To build such chains there are chainBefore and chainAfter methods.

XML Tranformation Example

For instance, let's write XML transformer, that converts transformation instructions of <?include-file fname ?> form to the contents of fname file.

/*
 * this program illustrate how to build own processing instructions handlers.
 * Level 0:
 *   handle XML process instruction <?include fname >
 * change during processing to content of file (as CharData) or to  
 * processing instruction <?error-opening-file fname>
 */

using namespace CASL;
using namespace std;

/**
 * So, we derive our transformer from XML transformer.
 **/
class PIIncludeHandler: public XMLTransformer
{
public:

  /**
   * and overload method 'processPI'
   **/
  bool processPI(WStringChunk& piName, WStringChunk& piBody, XMLContext& ctx);

};

/**
 *@param piName - name of processing instruction. (must be 'include')
 *@param piBody - body of processing instruction. in our case: name of
 * file, may-be surrounded by extra whitespaces.
 *@return true, if we does not handle this instruction, and what to pass it
 *   to next handlers in chain, otherwise 
 *   (i. e. if this is our instruction) - false.
 **/
bool PIIncludeHandler::processPI(WStringChunk& piName, 
                                 WStringChunk& piBody, 
                                 XMLContext& ctx)
{
 cerr << "processPI" << endl;
 std::string sPIName = CharConventer::toEncoding(piName,"ASCII").to_string();
 cerr << "piName=" << sPIName << endl;
 if (piName.equalASCII("include")) { // we must use ASCII name.
   string fname = Utils::toASCII(piBody); 
    // delete extra spaces.
   int wspos=fname.find_first_not_of(" \t\r\n");
   fname=fname.substr(wspos, fname.find_last_not_of(" \t\r\n")-wspos+1);
   std::ifstream input(fname.c_str()); // try to open file.
   if (!input) {
          // create new PI 'error-opening-file'
     WStringChunk newPI=Utils::fromASCII("error-opening-file");
          // send one.
     sendPI(newPI,piBody,ctx);
   }else{
     // copy all as sequence of CharData items.
     while(!input.eof()) {
        string buff;
        input >> buff;
        if (!input.eof()) buff+="\n";
        WStringChunk content = CharConventer::toUtf16(buff,"utf8");
        sendCharData(content,ctx);
     }
     input.close();
   }
   // As we handle this instruction, does not pass it up.
   return false;
 } else {
   // this is not our instruction - so simple return true.
   return true;
 }
}

The example is in the demo/XML/PIInclude directory of source CASL distributive.

When studying the example you should pay attention to utilities and symbols transformation classes usage: corresponding API description is Utils and CharConventer

XMLService

Now let's see how to use our transformer.

CASL provides static methods of XMLService class API

Here is code fragment, that starts our transformer:

01 try {
02  ifstream input(inputFileName.c_str()); 
03 if (!input) {
04    errors() << "Can't open file " << inputFileName << 
05                " for reading!" << endl;
06    return;
07 }
08 ofstream output(outputFileName.c_str());
09 if (!output) {
10    errors() << "Can't open file " << outputFileName << 
11                " for writing!" << endl;
12    return;
13 }
14 // do transformation:
15 //   we can cath errors in hight-level block
16 // create transformer.
17 auto_ptr<XMLTransformer> tr(XMLService::createXMLTransformer(input,output));
18
19 // and chain our transformer into.
20 PIInclude0Handler myTransformer;
21 tr->chainAfter(myTransformer,false);
22
23 // now create context and run all.
24 XMLContext ctx;
25 tr->process(ctx);
26
27 // That's all
28 input.close();
29 output.close();
30 }catch(const XMLException& ex){
31  errors() << ex.what() << endl;
32 }

Notice lines from 14 till 25 : we create XMLTransformer, bound to input stream and output stream. After, we add our transformer to the chain, create XMLContext and start parsing process.

XMLContext

Now let's consider XMLContext class. API You use the class instances to transfer information between different stges of XML processing.

Changes

  1. 9.07.2002 - created.



Footnotes

... std::istream).1
This requirement doesn't restrict commonness, for data streams, that you get from net can be arranged in form of specialized C++ streams

next_inactive up previous
GradSoft