You can parse the XML document using the two methods , SAX and DOM. When you parse the XML document using DOM, it occupies greater memory space to represent data in a tree structure, which results in slow performance. SAX overcomes the drawbacks of the DOM parser, and provides fast and efficient use of memory by reading the document in chunks . The Expat parser implements the SAX parser.
You can update XML documents by adding elements and attributes, removing elements, and changing the text of the XML document. For example, an XML document contains information pertaining to the students of a school. You need to add information about the students who have enrolled in a particular semester, and remove information about the students who have left the school.
To modify the information in the XML document, you need to create a filter by implementing the AbstractFilter class.
Listing 2-7 shows how to add information pertaining to a student in the XML document, using SAX:
<?php include_once("/class_sax_filters.php"); class FilterAddStudent extends AbstractFilter { var $studentDetail=Array(); function AddStudent($id, $name, $age, $address, $standard) { $detail=Array(); $detail["id"]=$id; $detail["name"]=$name; $detail["age"]=$age; $detail["address"]=$address; $detail["standard"]=$standard; $this->studentDetail[]=$detail; } function StartElementHandler($element_name, $attributes) { $this->listener->StartElementHandler($element_name, $attributes); if($element_name=="STUDENTDETAIL") { foreach($this->studentDetail as $student) { $this->listener->StartElementHandler("STUDENT", Array("id" =>$student["id"])); //For student name $this->listener->StartElementHandler("NAME", Array()); $this->listener->CharacterDataHandler($student["name"]); $this->listener->EndElementHandler("NAME"); //For student age $this->listener->StartElementHandler("AGE", Array()); $this->listener->CharacterDataHandler($student["age"]); $this->listener->EndElementHandler("AGE"); //For student address $this->listener->StartElementHandler("ADDRESS", Array()); $this->listener->CharacterDataHandler($student["address"]); $this->listener->EndElementHandler("ADDRESS"); //For student standard $this->listener->StartElementHandler("STANDARD", Array()); $this->listener->CharacterDataHandler($student["standard"]); $this->listener->EndElementHandler("STANDARD"); $this->listener->EndElementHandler("STUDENT"); } } } function EndElementHandler($element_name) { $this->listener->EndElementHandler($element_name); } function CharacterDataHandler($data) { $this->listener->CharacterDataHandler($data); } } $f1 = new ExpatParser("student.xml"); $f1->ParserSetOption(XML_OPTION_CASE_FOLDING, 0); $f2 = new FilterAddStudent(); $f2->AddStudent("S003", "Jack", "14","New York","9"); $f2->AddStudent("S004", "Jim", "14","New York","9"); $f3 = new FilterOutput(); $f2->SetListener($f3); $f1->SetListener($f2); $f1->Parse(); ?>
In the above listing:
The FilterAddStudent filter is implemented using the AbstractFilter class.
The FilterAddStudent filter contains the AddStudent() function that adds records of the students to the XML document.
The AddStudent() function stores the student details in the StudentDetail array, which is accessed by the event handlers to add new student records in the existing XML document.
Listing 2-8 shows the original XML document:
<?xml version="1.0" ?> <studentdata> <student> <name id="s001">George</name> <age>15</age> <address>New York</address> <standard>10</standard> </student> <student> <name id="s001">John</name> <age>15</age> <address>New York</address> <standard>10</standard> </student> </studentdata>
Figure 2-3 shows the output of Listing 2-7:
Using SAX, you can remove data from the XML document by creating a filter that is implemented by the AbstractFilter class, as shown in Listing 2-9:
<? include_once("/class_sax_filters.php"); class FilterRemoveStudent extends AbstractFilter { var $studentDetail = Array(); var $flag = 0; function RemoveStudent($id) { $this->studentDetail[] = $id; } function StartElementHandler($element_name, $attributes) { if($element_name == "STUDENT") { if(in_array($attributes["ID"],$this->studentDetail)) { $this->flag = 1; } } if(!$this->flag) { $this->listener->StartElementHandler($element_name, $attributes); } } function EndElementHandler($element_name) { if (!$this->flag) { $this->listener->EndElementHandler($element_name); } else { if($element_name=="STUDENT") { $this->flag=0; } } } function CharacterDataHandler($data) { if(!$this->flag) { $this->listener->CharacterDataHandler($data); } } } $fep = new ExpatParser("student.xml"); $frs = new FilterRemoveStudent(); $frs->RemoveStudent("S001"); $fou = new FilterOutput(); $frs->SetListener($fou); $fep->SetListener($frs); $fep->Parse(); ?>
In the above listing:
The FilterRemoveStudent filter is implemented using the AbstractFilter class.
The FilterRemoveStudent filter contains the RemoveStudent() function that removes the specified student s records from the XML document.
The RemoveStudent() function accepts the student id attribute as an argument. The RemoveStudent() function stores student ID in the StudentDetail variable, which is accessed by the event handlers to remove a student record from the existing XML document.
Figure 2-4 shows the output of Listing 2-9:
Querying a document refers to the process of traversing the XML document and searching for specific information. For example, an XML document contains information pertaining to the students of a school. You can query the XML document to search for the students who live in New York City.
Using SAX, you can query an XML document by creating a filter that is implemented by AbstractFilter, as shown in Listing 2-10:
<?php include_once("/class_sax_filters.php"); class FilterQueryStudent extends AbstractFilter { var $detail = Array(); var $stud = Array(); var $st; function RetrieveDetails() { return $this->detail; } function StartElementHandler($element_name, $attributes) { $this->st=''; if ($element_name <> "STUDENTDETAIL" && $element_name <> "STUDENT") { $this->st=$element_name; $this->stud[$this->st]=''; } } function EndElementHandler($element_name) { if($element_name == "STUDENT") { if(((trim($this->stud["ADDRESS"]))=="New York") && (trim($this->stud["AGE"])>=15)) { $this->detail[]=$this->stud; } $this->stud = Array(); } } function CharacterDataHandler($data) { if($this->st) { if(!empty($data)) { $this->stud[$this->st] .= $data; } } } } $tests=Array(); $f1 = new ExpatParser("student.xml"); $f2 = new FilterQueryStudent(); $f1->SetListener($f2); $f1->Parse(); $tests=$f1->listener->RetrieveDetails(); $num=count($tests); for($i=0;$i<$num;$i++) { foreach($tests[$i] as $key => $value) { print "<b>$key=$value</b><br/>"; } } ?>
In the above listing:
The AbstractFilter class implements the FilterQueryStudent filter.
The FilterQueryStudent filter contains the RetrieveDetails() function, which retrieves the records of students that satisfy the specified condition.
The EndElementHandler() function checks if the address of the student is New York and the age of the student is greater than or equal to 15.
Figure 2-5 shows the output of Listing 2-10:
Using SAX, you can generate an XML document from various sources, such as database, text file, and objects. You need to create a parser by implementing the AbstractSAXFilter class for generating the XML document.
For example, you can use the content of the student.txt text file to write an XML document. The student.txt file is shown below:
George, English John, French Jack, Physics Jim, French Jack, English Jim, Physics George, Physics John, Physics
Convert the student.txt text file into an XML document, using SAX, as shown in Listing 2-11:
<?php include_once("/class_sax_filters.php"); class StudentParser extends AbstractSAXParser { var $studentDetail = Array(); function StudentParser($textfile) { $xml_parser=new ParseStudent(); $xml_parser->ParseTextFile($textfile); $this->studentDetail=$xml_parser->GetStudents(); } function Parse() { $this->StartElementHandler($this,"STUDENTDETAIL",Array()); foreach($this->studentDetail as $student => $subjects) { $this->StartElementHandler($this, "STUDENT",Array()); $this->StartElementHandler($this, "NAME",Array()); $this->CharacterDataHandler($this, XmlEntities($student)); $this->EndElementHandler($this,"NAME"); $this->StartElementHandler($this, "SUBJECTS",Array()); foreach ($subjects as $subject) { $this->StartElementHandler($this, "SUBJECT",Array()); $this->CharacterDataHandler($this, XmlEntities($subject)); $this->EndElementHandler($this,"SUBJECT"); } $this->EndElementHandler($this, "SUBJECTS"); $this->EndElementHandler($this, "STUDENT"); } $this->EndElementHandler($this,"STUDENTDETAIL"); } } // Class that writes the XML data manually. class ParseStudent { var $studentDetail = Array(); function ParseTextFile($textfile) { $fp=fopen($textfile,"r"); if (!$fp) { return 0; } $text=fread($fp, filesize($textfile)); return $this->ParseText($text); } function GetStudents() { return $this->studentDetail; } function ParseText($text) { $entries = Array(); $entry = Array(); $entries = explode("\n",$text); foreach( $entries as $entry) { $entry = chop($entry); $entry = explode(",", $entry); if (!isset($this->studentDetail[$entry[0]])) { $this->studentDetail[$entry[0]]=Array(); } $this->studentDetail[$entry[0]][]=$entry[1]; } return 1; } } // Function that overwrites the special character with the XML entities. function XmlEntities($data) { $pos=0; $len=strlen($data); $escdata =""; for(;$pos<$len;) { $char=substr($data,$pos,1); $num = Ord($char); switch($num) { case 34: $char= ""; break; case 38: $char = "&"; break; case 39: $char = "'"; break; case 60: $char = "<"; break; case 62: $char = ">"; break; default: if ($num < 32) $char = ("&#".strval($num).";"); break; } $escdata .= $char; $pos++; } return $escdata; } $f1=new StudentParser("student.txt"); $f2=new FilterOutput(); $f1->SetListener($f2); $f1->Parse(); ?>
In the above listing:
The parser, StudentParser, parses the student.txt text file, using the ParseStudent parsing class.
The parsing class reads the text file and stores the content according to the number of lines in the text file.
The chop() function stores the content of text file in the entry array, and the explode() function splits the text file using a string delimiter .
The comma delimiter divides each line into two words, and stores these words in the studentDetail array.
Figure 2-6 shows the output of Listing 2-11:
Note | You can create a well- formed XML document by encoding the required functions. |
Using SAX, you can create PHP objects from an XML document. The SAX parser creates objects corresponding to each element in the XML document. These objects are represented as PHP objects using the SAX filters, and their references are stored in an array. For example, if an XML document contains information pertaining to students; it can be represented as the student object.
Listing 2-12 shows the content of the XML file that contains information pertaining to students:
<?xml version="1.0"?> <studentdetail> <student> <name>George</name> <marks>75</marks> </student> <student> <name>John</name> <marks>85</marks> </student> </studentdetail>
The above listing shows the elements of the XML document that are converted to the PHP objects.
The parser parses the XML document, finds the <student> tag, creates the student object, and stores its reference in an array. When the parser finds the <name> and <marks> tags, it assigns the value to the name and marks property of the student objects respectively.
Listing 2-13 shows how to create PHP objects from the XML document:
<?php include_once("/class_sax_filters.php"); class Student { var $name; var $marks; function GetName() { return $this->name; } function GetMarks() { return $this->marks; } function SetName($name) { $this->name=$name; } function SetMarks($marks) { $this->marks=$marks; } } class FilterNull extends AbstractFilter { } class FilterStudentObject extends AbstractFilter { var $count=0; var $student; var $sub_element=0; var $studentDetail=Array(); function GetStudents() { return $this->studentDetail; } function StartElementHandler($element_name, $attributes) { if($element_name=="STUDENT") { $this->studentDetail[]=new Student(); $this->count=1; } else { if($this->count) { $this->sub_element=$element_name; } } $this->listener->StartElementHandler($element_name, $attributes); } function EndElementHandler($element_name) { $this->sub_element=0; if($element_name == "STUDENT") { $this->count=0; } $this->listener->EndElementHandler($element_name); } function CharacterDataHandler($cdata) { if($this->count && $this->sub_element) { $getMethod="get".strtoupper(substr($this->sub_element,0,1)).substr ($this->sub_element,1);($this->sub_element,0,1)).substr($this->sub_element,1); $sub=$this->studentDetail[count($this->studentDetail)-1]->$getMethod(); $this->studentDetail[count($this->studentDetail)-1]->$setMethod($sub.$cdata); } $this->listener->CharacterDataHandler($cdata); } } $f1=new ExpatParser("student.xml"); $f2=new FilterStudentObject(); $f3=new FilterNull(); $f2->SetListener($f3); $f1->SetListener($f2); $f1->Parse(); $studentDetail=$f1->listener->GetStudents(); print_r($studentDetail); $num=count($studentDetail); print "<br/>"; for($i=0;$i<$num;$i++) { foreach($studentDetail[$i] as $key => $value) { print "<b>$key=$value</b></br/>"; } } ?>
In the above listing:
The parser creates the objects of the student element and stores them in the studentDetail array.
The Student class creates the functions for retrieving the XML data. The StudentCreateObject filter parses the XML document and creates the objects corresponding to each element.
The FilterNull class is an empty user -defined class that does not contain any function. This class specifies that the output of the StudentCreateObject filter is not displayed in the XML format.
Figure 2-7 shows the output of Listing 2-13:
Note | The print_r() function displays how the array elements are stored in the array. |