PARSING XML WITH PHP, PART 2
Last week, I discussed PHP's XML capabilities, set up an XML parser in
PHP, and created the callback functions. The purpose of all of these
functions thus far is to set up the parser so it can handle the various
XML
events as they occur. Of course, you'll need to initiate the parsing
process.
One reason to use an event-based parser over a tree-based parser is
that
it's more compatible with large XML documents. Parsing large documents
into a tree in memory means that the entire document has to be in
memory.
Using event-based parsing, you only get a portion of the data as XML
events occur, allowing your program to handle larger documents and more
of
them.
Because you don't want to read the document into memory all at once,
there needs to be a mechanism that lets you "chunk" the XML data into
the
parser. PHP's xml_parse() function lets you send data in chunks and
allows
you to specify a condition that tells the parser when the end of the
chunks have been reached. The syntax of the xml_parse() function is:
xml_parse($parser, $chunk, $is_final_chunk);
PUTTING THE PIECES TOGETHER
Now we have all of the necessary pieces of the puzzle to build a simple
application that illustrates how to create a PHP XML parser. We'll
start
with a simple XML document, as follows:
John Doe
Doe & Dough Inc.
23339
900 North Michigan Ave.
Chicago
IL
60614
Next, we'll create a PHP script that will implement a handler for the
start and end elements as well as the character data. Let's assume that
the
script needs to extract just the account number and company name from
this XML document and display them. Here's the full PHP script:
function startElement($parser, $name, $attrs) {
global $gotCompanyName, $gotAccountNumber;
if ($name == "CompanyName") $gotCompanyName = true;
if ($name == "Account") $gotAccountNumber = true;
}
function endElement($parser, $name) {
global $gotCompanyName, $gotAccountNumber;
if ($gotCompanyName && $name == "CompanyName") $gotCompanyName = false;
if ($gotAccountNumber && $name == "Account") $gotAccountNumber = false;
}
function characterData($parser, $value) {
global $gotCompanyName, $gotAccountNumber, $companyName,
$accountNumber;
if ($gotCompanyName) $companyName = $value;
if ($gotAccountNumber) $accountNumber = $value;
}
$parser = xml_parser_create();
$file = "data.xml";
$gotCompanyName = false;
$gotAccountNumber = false;
$companyName = "";
$accountNumber = "";
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
xml_set_element_handler($parser, "startElement", "endElement");
xml_set_character_data_handler($parser, "characterData");
if ($fp = fopen($file, "r")) {
while ($data = fread($fp, 1024)) {
xml_parse($parser, $data, feof($fp));
}
}
xml_parser_free($parser);
print "Company name = $companyName
\n";
print "Account number = $accountNumber
\n";
?>
As you can see, this is a relatively simple script. There are three
functions for handling the start element, end element, and character
data
events. The line that calls xml_parser_create() is where the script
really
starts. This line instantiates a new XML parser that will be used
throughout the rest of the script. Next, we initialize a few variables
for
handling the name of the file containing the XML document, identifying
if an
element has been found, and storing the data we're looking for.
Then we disable the case folding option as previously discussed and
register our callback functions so that the parser knows where to send
events
when they occur. Then we open the file containing the XML document and
read it in chunks of 1,024 bytes (which, in this case, will be the
entire
file). As new data is read from the file, we call the xml_parse()
function and send the new chunk. As the parser receives data, it will
use our
callback functions. It does not wait for the last chunk before it calls
the
handler functions.
As the callback functions are called, they will locate the elements
called CompanyName and Account and store the value of these elements
into
global variables named $companyName and $accountNumber, respectively.
Once
the parsing is complete, we free the parser resources and display the
values found in the XML document.
Brian Schaffner is a senior consultant for DMR Consulting, a Fujitsu
company. He provides architecture, design, and development support for
DMR's
Telcom360 group.
----------------------------------------