Author: Liu Yanqing
Source: http://www.ccidnet.com/tech/web/2002/01/07/92_3901.html
Introduction
Perl 's popularity is directly related to the booming of the Internet. In the early days of the development of the Internet, people found that only the static HTML document cannot generate a valid interactive environment, which introduces the concept of public gateway interface (CGI). PERL powerful features and easy expansion characteristics make it a developing CGI application most natural choice, and thus quickly becomes the preferred language of the CGI script. CGI itself is not a perfect. However, since the favor of many developers, CGI's application is still very extensive, and there is no indication that it will "retire" in the near future.
CGI :: xmlapplication provides a module based on XML and can be used as a traditional CGI script. Typical CGI :: XMLApplication scripts include three parts: a small number of executable scripts that provide support for this application, implement the logic modules of various managers methods, may have one or more XSLT style sheets according to the application status, The XSLT style sheet can transform the results returned to the module into a browser to display the format to the user.
Below we briefly introduce the application of CGI :: XMLApplication.
Example 1: CGI XSLT Gateway
CGI :: XMLApplication assumptions, participating in a project design and developers use XSLT style sheets to separate applications logic and representation, which can make this separation very direct, nor will it affect the project. Developers can make the setStylesheet return to the location of the XSLT style sheet that matches the current application status. The conversion of the application established DOM tree, the XSLT parameter passes to the conversion engine, and the conversion content is transparent to the user's transmission of the browser.
In order to focus on this separation, our first example is not a web application in the traditional sense, but a universal XSLT gateway that can be added to the server's CGI-BIN, converting the entire XML content directory tree into compliance The requested browser format, and all of this is transparent to the author of the user, style sheet, and documentation.
The first step is to establish a CGI script that connects to the client's request and application. We hope that the XML document can be easily browsed through the URL and makes the hyperlink between the creation of these documents is very intuitive. Therefore, we will create a CGI script without an extension to use it as a node in the URL path, and all the contents of the node will explain in a virtual document environment containing XML content. In this case, we call CGI as a style sheet selection.
Use strict;
Use lib '/ path / to / secure / webapp / libs'
Use xslgateway;
Use cgi QW (: standard); My $ = cgi-> new ();
MY% context = ();
MY $ GATEWAY_NAME = 'STYLECHOOOSER';
After loading the appropriate module and setting some variables that are valid throughout the script, we start to add some domains to% Context that is passed to the class of the application logic. In this application, we only transfer the requirements of the URL (Request entry) to the right of the script file path and the Style entry containing data stored in the query parameter style.
$ context {request} = $ q-> URL (-path => 1);
$ context {request} = ~ s / ^ $ GATEWAY_NAME / /? / /;
$ context {request} || = 'index.xml';
$ context {style} = $ q-> param ('style') if $ q-> param ('style');
Finally, we created an instance of the Xslgateway logic class, and the% Context as a unique parameter by calling its RUN method processing request. MY $ app = xslgateway-> new ();
$ app-> run (% context);
The CGI script is completed. Below we create the XSlgateway module that completes most of the work:
Package xslgateway;
Use strict;
Use Vars QW (@ISA);
Use cgi :: xmlapplication;
Use xml :: libXML;
@ISA = QW (CGI :: XMLApplication);
As I mentioned in the introduction, CGI :: XMLApplication works by event call: execution of a given method in the application class depends on an input of a specified domain (in general, the button used to submit the table. Name.), Two call methods must be performed: SelectStylesheet and RequestDom methods.
SelectStylesheet Returns the full file system path for the XSLT style sheet. For the sake of simplicity, we assume that the style sheet will be saved in a single directory. We can provide additional style sheets through the $ context -> {style} domain, increasing the flexibility of the system.
Sub selectionstylesheet {
MY $ SELF = Shift;
MY $ context = shift;
MY $ style = $ context -> {style} || 'default';
MY $ style_path = '/ opt / www / htdocs / stylesheets /';
RETURN $ style_path. $ style. '.xsl';
}
Next, we need to create a RequestDom method, which will return the XML: Libxml DOM expression of the transmitted XML document. Since our gateway only applies to static files, we need to parse the document using XML :: libXML and return the results tree.
Sub RequestDom {
MY $ SELF = Shift;
MY $ context = shift;
MY $ XML_FILE = $ Context -> {Request} || 'Index.xml';
MY $ doc_path = '/ opt / www / htdocs / xmldocs /';
MY $ Requested_Doc = $ doc_path. $ xml_file;
MY $ PARSER = XML :: LIBXML-> NEW;
MY $ doc = $ parser-> parse_file ($ Requested_Doc);
Return $ doc;
}
At this point, our CGI scripts have been securely run safely in the server's CGI-BIN directory, and upload some XML documents and one or two XSLT style sheets in some appropriate directories. Below we can start to test our work results. Request for http://localhost/cgi-bin/stylechooser/mydocs/somefile.xml will make the Internet server from the / OPT / WWW / HTDOCS / XMLDOCS / directory, use / opt / wwww / htdocs / stylesheets / style sheet default.xsL converts the file and transfer it to the customer.
If we need, we can expand this basic framework, for example, you can add some find components to the style sheet to add some findings, select the appropriate style sheet, you can set or read HTTP cookies, modify the site. Example 2: A simple shopping system
In this example, we will create a simplified web application, shopping system using CGI :: XMLApplication.
As with the previous example, the part related to cgi-bin is still very small in this application. What we need is just the RUN () method that initializes the CustomerORDER application class and calls it. This time, we will use Vars in cgi.pm as the PARAMS domain of% Context:
Use strict;
USE CGI QW (: standard);
Use lib '/ path / to / secure / webapp / libs'
Uses USE CustomerOrder;
MY $ = cgi-> new ();
MY% context = ();
$ context {params} = $ q-> vars;
MY $ app = CustomerORDER-> New ();
$ app-> run (% context);
In this example, we assume that the product information in the application is stored in the relational database, and the product list is not too long, so that we will not have multi-screen in the app to display the trouble: the user enters the number of products to be ordered. Data input screen, display the list of subscribers and the total price of the selected item, show the prompt that the order has been processed. For the sake of simplicity, we have no issues such as delivery and financial data here.
Package CustomerOrder;
Use strict;
Use Vars QW (@ISA);
Use cgi :: xmlapplication;
Use xml :: libxml :: sax :: builder;
Use xml :: generator :: dbi;
USE DBI;
@ISA = QW (CGI :: XMLApplication);
After loading the necessary modules and definitions from the CGI :: XMLAPLICATION, we started to create an event call related to a variety of states. First, we must register these events by creating a registerevents () method. In this example, we will register the ORDER_CONFIRM and ORDER_SEND method, which sets the ScreenStyle field in% Context. Later, we will use this attribute to define which one of the three XSLT style sheets should be used when the data is displayed.
It should be noted that these events will be mapped to the actual subroutine that implements their actual subroutines, the naming rules of the subroutine are Event_
# Registration and event call
Sub registerevents {
Return QW (ORDER_CONFIRM ORDER_SEND);
}
Sub event_order_confirm {
MY ($ Self, $ context) = @_;
$ context -> {screenstyle} = 'order_confirm.xsl';
}
Sub Event_order_send {MY ($ Self, $ Context) = @_;
$ context -> {screenstyle} = 'order_send.xsl';
}
If there is no other event request, Event_Default is executed by default. In this case, we only use it to set the ScreenStyle field to a suitable value.
Sub Event_Default {
MY ($ Self, $ context) = @_;
$ context -> {screenstyle} = 'order_default.xsl';
}
Event_init methods are performed each request, and it is always performed before other methods, which makes it ideal for initialization of the part used by other events. In this example, we use it to return to the product information obtained from the database from the database, the initial DOM tree.
Sub Event_init {
MY ($ Self, $ context) = @_;
$ context -> {domtree} = $ self-> fetch_recordset ();
}
After the State-Handler method is completed, we need to perform the necessary SelectStylesheet and RequestDom methods.
As in the first example, we assume that all the style sheets of all applications are stored in the same directory on the server. What we need is to return the route specified by the value of $ context -> {screenstyle} and added to the end.
# App Config and Helpers
Sub selectionstylesheet {
MY ($ Self, $ context) = @_;
MY $ style = $ context -> {screenstyle};
MY $ style_path = '/ opt / www / htdocs / stylesheets / cart /';
RETURN $ style_path. $ style;
}
Before studying the RequestDom handler, let's study the fetch_recordset helper method in detail.
What needs to be remembered is that the work we have to do is to select information about the subscribed product from a relational database, but the data passed to the XSLT processor must be a DOM tree. In this example, we don't have a programming method, but use XML :: Generator :: DBI, which generates SAX data from the data obtained by executing the SQL SELECT statement. The DOM tree created is to create an instance of XML :: LIBXML :: Sax :: Builder (it creates an XML: LIBXML DOM tree from the SAX event).
SUB FETCH_RECORDSET {
MY $ SELF = Shift;
MY $ SQL = 'SELECT ID, NAME, PRICE AUTORTE'
MY $ dbh = dbi-> connect ('DBI: Oracle: WebClients ",
'Chico',
'snordfish')
|| DIE "Database Connection COULDN '
BE Initialized: $ dbi :: errstr / n ";
MY $ Builder = XML :: LIBXML :: Sax :: Builder-> New ();
MY $ GEN = XML :: Generator :: DBI-> New (Handler => $ Builder,
DBH => $ dbh,
RootElement => 'Document',
QueryElement => 'ProductList',
RowElement => 'Product');
MY $ DOM = $ gen-> Execute ($ SQL) || DIE "Error Building Dom Tree / N";
Return $ DOM;
The fetch_recordset method has completed another important task, but it returns the DOM tree contains only part of the information we want to send to customers, and we must also obtain the number of products entered, in addition, there is a need to provide a total of a subscription product.
Sub RequestDom {
MY ($ Self, $ context) = @_;
MY $ root = $ context -> {domtree} -> getDocumentElement ();
MY $ grand_TOTAL = '0';
In order to put the current order as part of a larger document, we will traverse all product elements and add a child element in each row. The value can be obtained from the $ context -> {params} domain.
Foreach MY $ ROW ($ root-> findnodes ('/ document / productlist / product)) {
MY $ ID = $ ROW-> FindValue ('id');
MY $ COST = $ row-> FindValue ('price');
MY $ quantity = $ context -> {params} -> {$ ID} || '0';
MY $ item_ TOTAL = $ quantity * $ cost;
$ grand_total = $ item_total;
# Add the order quantity and item totals to the tree.
$ ROW-> AppendTextChild ('Quantity', $ Quantity);
$ row-> appendtextchild ('Item-Total', $ Item_Total);
}
Finally, we will add some meta information about orders, and the method is to add an element in the root element having an element, which contains the current value of the currently selected goods.
$ grand_total || = '0.00';
MY $ INFO = XML :: LIBXML :: Element-> New ('instance-info');
$ info-> appendtextchild ('Order-Total', $ Grand_Total);
$ root-> appendchild ($ INFO);
RETURN $ context -> {domtree};
}
Careful readers may have noticed that this very simple application does not do any actual things in the order_send method. Decide how to deal with these data is the most relevant part of the product ordering application with specific shopping sites.
Conclude
CGI :: XMLApplication provides a clear, modular isolation system for the programming of the CGI script, and the method of the modular isolation system, and it is worth studying it. In addition, it allows us to avoid entanglement of some details, and concentrate on solve the main problems.