A Sample PHP XML Application

Một phần của tài liệu Professional PHP Programming phần 5 pptx (Trang 27 - 42)

To give a simple example of what can be done with XML and PHP, we will implement a simple "Book Information Site". This site will allow users to search books using the title, author or ISBN of the book as the search criterion. Alternatively, the user can view the complete list of books. After the user has searched for all books of interest, he or she can view the table of contents of the book.

All the information about the books will be stored in an XML file.

Before looking at the code of the application, let us first look at the user interface of the application to get a feel for it.

The main page of the application allows the user to search books using the title, author or ISBN of the book as the search criterion; alternatively, users can view the complete list of books:

To searching for a book, the user enters the search keyword in the Search Keyword text input box, and specifies the search category using the Search Books By list box. In the above figure, the search keyword is 'Java', and the search will be by title, so the application will search for all books with the word "Java" in the title.

To view all the books in the file, the user can click on the Complete list of books button.

The results of the search are shown in the figure below. Clicking on the title of a book will present the user with the table of contents for that book:

The other option available from the main page is to view the complete list of all the books. Again, the title of the book acts as link which the user can click to view the book's table of contents:

This figure displays the table of contents of the book, selected by the user from Complete List of Books or Search Page.

Now, after having looked at the screen shots of the application, we understand the functionality of the application. So it is the right time to look at the code.

The book details are stored in XML files in order to enable smart searches, which form an important requirement of the application. A relational database could have been used for storing the data, but it would not have made sense to install a relational database for this simple application. Another important feature of XML is that it stores data in plain text files, so the data can easily be exchanged between applications, even on different platforms. It is even human-readable.

The XML file books.xml stores the book details. The following is a sample books.xml file containing details of three books. First we have the DTD:

<?xml version="1.0"?>

<!DOCTYPE listofbooks[

<!ELEMENT book (title, authors, isbn, price, toc)*>

<!ELEMENT title (#PCDATA)>

<!ELEMENT authors (author*)>

<!ELEMENT author (#PCDATA)>

<!ELEMENT isbn (#PCDATA)>

<!ELEMENT price (#PCDATA)>

<!ELEMENT toc (chapters, appendixes)>

<!ELEMENT chapters (chapter)*>

<!ELEMENT chapter (#PCDATA)>

<!ELEMENT appendixes (appendix)*>

<!ELEMENT appendix (#PCDATA)>

<!ATTLIST price currency CDATA #REQUIRED>

<!ENTITY book 1861002947 SYSTEM "1861002947.xml">

<!ENTITY book 1861002971 SYSTEM "1861002971.xml">

<!ENTITY book 1861002777 SYSTEM "1861002777.xml">

]>

Then comes the data itself. The root element which encloses the data is named <listofbooks>.

Each book is represented by a <book> element, which contains child elements for each item of information stored about the book, such as <title>, <isbn> and <price>. Since there may be more than one author for a book, there is an <authors> element for each book, which has a child

<author> element for each author. The table of contents for the book is stored in another XML file, so we use an external entity reference to refer to that:

<listofbooks>

<book>

<title>Beginning Web Development with Visual Interdev 6</title>

<authors>

<author>Andrew Mumford</author>

</authors>

<isbn>1-861002-94-7</isbn>

<price currency="USD">39.99</price>

&book 1861002947;

</book>

<book>

<title>Professional Java Server Programming</title>

<authors>

<author>Danny Ayers</author>

<author>Hans Bergsten</author>

<author>Mike Bogovich</author>

<author>Jason Diamond</author>

<author>Matthew Ferris</author>

<author>Marc Fleury</author>

<author>Ari Halberstadt</author>

<author>Paul Houle</author>

<author>Sing Li</author>

<author>Piroz Mohseni</author>

<author>Andrew Patzer</author>

<author>Ron Phillips</author>

<author>Krishna Vedati</author>

<author>Mark Wilcox</author>

<author>Stefan Zeiger</author>

</authors>

<isbn>1-861002-77-7</isbn>

<price currency="USD">59.99</price>

&book 1861002777;

</book>

<book>

<title>Beginning Linux Programming Second Edition</title>

<authors>

<author>Neil Matthew</author>

<author>Richard Stones</author>

</authors>

<isbn>1-861002-97-1</isbn>

<price currency="USD">39.99</price>

&book 1861002971;

</book>

</listofbooks>

The XML file 1861002777.xml contains the table of contents of the "Professional Java Server Programming" book. Each book should have one such file containing the table of contents of the book.

In this case, the root element is named <toc>, and this contains two elements – <chapters> and

<appendices>. These contain child <chapter> and <appendix> elements respectively:

<?xml version="1.0"?>

<toc>

<chapters>

<chapter>Web Application Development</chapter>

<chapter>Introduction to Servlets</chapter>

<chapter>Error Handling and Event Logging</chapter>

<chapter>Sessions and Session Tracking</chapter>

<chapter>Using the Servlet Context</chapter>

<chapter>Dynamic Content Generation</chapter>

<chapter>Introduction to JavaServer Pages</chapter>

<chapter>Connecting to Databases</chapter>

<chapter>Connection Pooling</chapter>

<chapter>Servlet Chaining</chapter>

<chapter>Servlet Communications</chapter>

<chapter>Distributed Computing with Servlets</chapter>

<chapter>JavaMail and Servlets</chapter>

<chapter>Introducing XML</chapter>

<chapter>Weeds of El-Limon 2</chapter>

<chapter>Bug Tracker Case Study</chapter>

<chapter>

Bug Tracker Case Study: Elaboration, Construction and Transition </chapter>

<chapter>Moving from CGI to Servlets</chapter>

<chapter>Internationalizing Web Sites</chapter>

<chapter>Smart Servlets</chapter>

<chapter>Server Programming with JNDI</chapter>

<chapter>Using LDAP and Java</chapter>

<chapter>Enterprise JavaBeans</chapter>

<chapter>Indexing and Searching</chapter>

<chapter>JINI and JavaSpaces: Servers of the Future</chapter>

<chapter>Working With JavaSpaces</chapter>

<chapter>Coding a Jini-based Website</chapter>

</chapters>

<appendices>

<appendix>HTTP</appendix>

<appendix>Java Object Streams and Serialization</appendix>

<appendix>Cryptography and Servlets</appendix>

<appendix>The LogWriter Class</appendix>

<appendix>UML Tutorial</appendix>

<appendix>JServ Configuration</appendix>

<appendix>ServletRunner and Java Web Server Configuration</appendix>

<appendix>JRun Configuration</appendix>

<appendix>JSDK API Reference</appendix>

<appendix>JavaServer Pages API Reference</appendix>

<appendix>JNDI API Reference</appendix>

<appendix>Core JavaMail / JAF API Reference</appendix>

<appendix>Core Jini API Reference</appendix>

<appendix>JavaSpaces API Reference</appendix>

<appendix>EJB Reference</appendix>

<appendix>JDBC Reference</appendix>

<appendix>Support and Errata</appendix>

</appendices>

</toc>

Apart from these XML files which contain the data, the application consists one HTML file and four PHP scripts. The main page of the application is the HTML page, named main.html:

<HTML>

<HEAD>

<TITLE>Book Information Site</TITLE>

</HEAD>

<BODY>

<BR><H1><B>Book Information Site</B></H1>

<BR><HR>

<H2><B>Search Books</B></H2>

After the title and page headers, the page contains a form with the ACTION attribute set to one of our PHP pages, search_books.php. This contains a <SELECT> element with options which allow the user to choose a category for the search ("title", "author" or "isbn"). The selected search category will be available in the search_books.php script through the $searchBy variable.

There is also a text box where the keyword for the search can be entered (this will be available to the PHP script as the $searchKeyword variable), and a submit button:

<FORM ACTION="search books.php" METHOD=GET>

<CENTER>

<TABLE>

<TR>

<TD>

<B>Search Books By</B>

</TD>

<TD>

<SELECT NAME=searchBy SIZE=1>

<OPTION>title <OPTION>author <OPTION>isbn </SELECT>

</TD>

</TR>

<TR>

<TD>

<B>Search Keyword</B>

</TD>

<TD>

<INPUT TYPE=TEXT NAME="searchKeyword">

</TD>

</TR>

<TR>

<TD> </TD>

<TD>

<INPUT TYPE="submit" VALUE="Submit">

</TD>

</TR>

</TABLE>

</CENTER>

</FORM>

The page also contains a second form with display_books.php as the processing script. This simply contains the submit button for displaying details of all the books:

<FORM ACTION="display books.php" METHOD=GET>

<CENTER>

<INPUT TYPE="submit" VALUE="Complete list of books">

</CENTER>

</FORM>

</BODY>

</HTML>

The file common.php contains common functions, which are used throughout the application. First we define some variables which we'll be using in all the PHP pages – the XML file which contains the data, a variable called $currentTag to hold the name of the element that is currently being parsed, and a number of variables to store the details for the book element that the parser is currently parsing:

<?php

$file = "books.xml";

$currentTag = "";

$titleValue = ""; // Value of the title element

$authorsValue = array(); // Array of the values of the author elements $isbnValue = ""; // Value of the isbn element

$priceValue = ""; // Value of the price element

$currencyValue = ""; // Value of the book element's currency attribute $descriptionValue = ""; // Value of the description entity reference

$authorCount=0; // Variable used to populate the $authorsValue array

We will also define an array to contain the book details:

$books = array(); // Contains the details of books.

Next we define the start element handler of the parser. We store the element name in the global variable $currentTag, so that the character data handler can identify the element that is currently being parsed. If the current element is <price>, we store the value of the currency attribute in the global variable $currencyValue:

function startElement($parser, $name, $attr) { global $currentTag, $currencyValue;

$currentTag = $name;

if (strcmp($name, "price") == 0) $currencyValue = $attr["currency"];

}

Then we define the end element handler. If the function is being called for a <book> element, it means that the parser has completed parsing a book element. We store the details of the book in the

$books array, and reinitialize the global variables to store the details of another book. If the function is called for an <author> element, we increment the $authorCount variable:

function endElement($parser, $name) {

global $titleValue, $authorsValue, $isbnValue, $priceValue, $currencyValue, $books, $authorCount, $descriptionValue;

if (strcmp($name, "book") == 0) {

$books[] = array("title"=>$titleValue, "authors" =>$authorsValue, "isbn" => $isbnValue, "price" =>$priceValue, "currency" =>$currencyValue,

"description" =>$descriptionValue) ; $titleValue = "";

$authorsValue = array();

$isbnValue = "";

$priceValue = "";

$authorCount=0;

$currencyValue="";

$descriptionValue = "";

} elseif (strcmp($name, "author")== 0) { $authorCount++;

$authorsValue[$authorCount] = "";

} }

Now we define the character data handler. Depending on the value of $currentTag, we concatenate

$data to the appropriate global variable:

function characterData($parser, $data) {

global $titleValue, $authorsValue, $isbnValue,$priceValue, $currentTag, $authorCount;

if (strcmp($currentTag, "title") == 0) { $titleValue .= $data;

} elseif (strcmp($currentTag, "author") == 0) { $authorsValue[$authorCount] .= $data;

} elseif (strcmp($currentTag, "isbn") == 0) { $isbnValue .= $data;

} elseif (strcmp($currentTag, "price") == 0) { $priceValue .= $data;

} }

Our last handler is for external entity references; we simply store the value of $systemId in the global variable $descriptionValue:

function externalEntityHandler($parser, $entityName, $base, $systemId, $publicId) { global $descriptionValue;

if (!systemId) return false;

$descriptionValue = $systemId;

return true;

}

The function readBookInfo() parses the XML document and returns an array containing the details of books. First, we create a parser, register our handlers and set the

XML_OPTION_CASE_FOLDING option of the XML parser to false to ensure that all the element names are converted to upper case:

function readBookInfo() { global $file, $books;

$xml parser = xml parser create();

xml set element handler($xml parser, "startElement", "endElement");

xml set character data handler($xml parser,"characterData");

xml set external entity ref handler($xml parser, "externalEntityHandler");

xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, false);

Next we open the XML file, read the data from the file in 4K chunks, and pass the data to the XML parser $xml_parser:

if (!($fp = fopen($file, "r"))) {

die("Could not open $file for reading") ; }

while (($data = fread($fp, 4096))) {

if (!xml parse($xml parser, $data, feof($fp))){

die(sprintf("XML error at line %d column %d",

xml get current line number($xml parser), xml get current column number($xml parser)));

} }

When we've finished parsing, we free the XML parser and return the global $books array:

xml parser free($xml parser);

return $books;

}

Now we need a function to print the details of a book in a row of an HTML table. We print the title of the book as an HTML link (with the HREF

"display_description.php?isbn=$isbnValue"). If the user clicks on this link, then the display_description.php script is called with the form variable $isbn containing the ISBN of the selected book:

function printBookInfo($titleValue, $authorsValue, $isbnValue, $priceValue, $currencyValue) {

print "<TR>";

print "<TD><A HREF=\"display description.php?isbn=$isbnValue\">

$titleValue</A></TD>";

print "<TD>";

for($j=0; $j<count($authorsValue)-1; $j++) { if ($j !=0)

print ",";

print " $authorsValue[$j] ";

}

print "</TD>";

print "<TD>$isbnValue</TD>";

print "<TD>$priceValue $currencyValue</TD>";

print "</TR>";

}

The function searchBooksByISBN() returns an array containing the details of the book with a given ISBN. The variable $books contains the details of all the books:

function searchBookByISBN($books, $isbn) { for($i = 0; $i < count($books); $i++) {

if (strcmp(trim($books[$i]["isbn"]), trim($isbn)) == 0) { return $books[$i];

} }

return null;

}

?>

Our next page, display_books.php, displays the details of all the books in the XML file:

<HTML>

<HEAD>

<TITLE>Complete list of Books</TITLE>

</HEAD>

<BODY>

<H1>Complete List of Books</H1>

<HR><BR>

After the page headers, we generate a table to display the details of books:

<TABLE BORDER=1>

<THEAD>

<TR>

<TH> title </TH>

<TH> authors </TH>

<TH> isbn </TH>

<TH> price </TH>

</TR>

</THEAD>

<TBODY>

<?php

require("common.php");

Within the table, we require the common.php file and call the readBookInfo() to parse the XML document. This returns an array containing the details of all the books in the file, which we store in the variable $books:

$books = readBookInfo();

Finally, we display the details of all the books. Details of each book are displayed in a separate row of the table:

for($i=0; $i<count($books); $i++) {

printBookInfo($books[$i]["title"], $books[$i]["authors"], $books[$i]["isbn"], $books[$i]["price"], $books[$i]["currency"]) ;

} ?>

</TBODY>

</TABLE>

</BODY>

</HTML>

The next script we'll look at is the search script, search_books.php. From this page the user can search the XML data for books matching the specified search criterion:

<HTML>

<HEAD>

<TITLE>Search Results</TITLE>

</HEAD>

<BODY>

<B>Search Results</B>

<HR><BR>

Again, we will display the results in a table, and require our common.php script and call the readBookInfo() function within the table body:

<TABLE BORDER=1>

<THEAD>

<TR>

<TH> title </TH>

<TH> authors </TH>

<TH> isbn </TH>

<TH> price </TH>

</TR>

</THEAD>

<TBODY>

<?php

require("common.php");

$books = readBookInfo();

If the search category is "ISBN", we print the details of the book with $searchKeyword as the value of its <isbn> element:

if (strcmp($searchBy, "isbn")== 0) {

if (($book = searchBookByISBN($books, $searchKeyword))) printBookInfo($book["title"], $book["authors"], $book["isbn"], $book["price"], $book["currency"]);

If the search category is "author", then we print the details of books where $searchKeyword is the name of one of the authors:

} elseif (strcmp($searchBy, "author")== 0) { for ($i=0; $i<count($books); $i++) { $authorsValue = $books[$i]["authors"];

for($j=0; $j<count($authorsValue)-1; $j++) {

if (strcmp(strtolower(trim($authorsValue[$j])), strtolower(trim($searchKeyword))) == 0) printBookInfo($books[$i]["title"],

$books[$i]["authors"], $books[$i]["isbn"], $books[$i]["price"], $books[$i]["currency"]) ;

} }

Finally, if the search is by title, we print the details of books whose title contains the

$searchKeyword:

} else if (strcmp($searchBy, "title") == 0) { for ($i=0; $i<count($books); $i++) {

if (strstr(strtolower(trim($books[$i]["title"])), strtolower(trim($searchKeyword)))) printBookInfo($books[$i]["title"],

$books[$i]["authors"], $books[$i]["isbn"], $books[$i]["price"],

$books[$i]["currency"]);

} } ?>

</TBODY>

</TABLE>

</BODY>

</HTML>

Our last page, display_description.php, displays the table of contents for the book with the specified ISBN:

<HTML>

<HEAD>

<TITLE>Table of Contents</TITLE>

</HEAD>

<BODY>

Một phần của tài liệu Professional PHP Programming phần 5 pptx (Trang 27 - 42)

Tải bản đầy đủ (PDF)

(86 trang)