parser = xml_parser_create(); xml_set_object($this->parser,$this); xml_set_element_handler($this->parser,"startHandler","endHandler"); xml_set_character_data_handler($this->parser,"cDataHandler"); $hl = new hierarchy_loader(); $this->cur_group = $hl->create_group_structure($schema_file,$xml_file); $this->cur_group->init_ids(); $this->xml_file = $xml_file; $this->head_tag = $this->cur_group->name; } function startHandler($xp, $element, $attribs) { $element = strtolower($element); //echo "START: $element \n"; if($element == $this->head_tag) { $this->cur_group->assign_ids(Group::$ids[$this->head_tag],Group::$ids[$this->head_tag], Group::$ids[$this->head_tag]); $this->template = ""; $this->get_entry = true; $this->found_error = false; } else if ($this->get_entry){ $found = false; while(!$found && !$this->found_error) { //First check to see if the element exists in the current group. Note that in; //subgroups, a field can only occur once. Otherwise, it is not possible; //to determine if a field marks the beginning of a new group or exists within; //the current group. The flexibility may be able to be improved for this in; //later versions.; if(array_key_exists($element,$this->cur_group->fields) && ($element != end($this->first_field))) { $this->template .= "$element "; $this->cur_tag = $element; $this->get_val = true; break; } //Then check to see if the element exists in any of the subgroups of the current group; //If the element is not in any of the subgroups then it must mean there are no more elements; //in the current group. I have set the condition that a group must contain at least one non-group; //element and it must be the first item in the group. Otherwise, it is not possible to determine; //to which group a field belongs. For example, a pna field, which is a field of a subgroup of; //se and sea, can not precede the sense it belongs to. Otherwise, it is not possible to determine; //whether the pna field belongs to the sense field before it or after it (if one exists). //$new_group = false; foreach($this->cur_group->groups as $group) { if(array_key_exists($element,$group->fields)) { $this->first_field[] = $element; //echo "moving down from ".$this->cur_group->name." to "; $new_group = clone $group; $new_group->assign_ids($this->cur_group->main_id, $this->cur_group->id, $this->cur_group->name); $new_group->parent = $this->cur_group; $this->cur_group->group_vals[$new_group->name][] = $new_group; $this->cur_group = $new_group; //unset($new->group->parent); unset($new_group); //echo $this->cur_group->name."\n"; $this->cur_tag = $element; $this->get_val = true; $this->template .= $group->name." ".$element." "; $found = true; break; } } //If the element did no exist in any subgroups, ascend up the hierarchy. If the element is; //not a member of the parent group, the variable 'new_group' will remain false and the; //while loop will begin again though with the parent group as the current group. I suppose; //this leads to some redundancy as the code will check in places it has alread looked, namely; //the current group. However, I believe the efficiency of the recursion, in general, makes up for it; if(!$found) { if($this->cur_group->name != $this->head_tag) { $this->template .= "/".$this->cur_group->name." "; } //echo "moving up from ".$this->cur_group->name." to "; if($this->cur_group->parent !== false) { $this->cur_group = $this->cur_group->parent; //echo $this->cur_group->name." \n"; array_pop($this->first_field); } else { $ref = $this->cur_group->field_vals["ref"][0]; $error = "LINE ".xml_get_current_line_number($this->parser); $error .= ": ERROR: XML does not match schema. ref: $ref. See field '$element'.\n"; $this->errors[] = $error; $this->found_error = true; break; } /* The following code handles a case of the following: /se /ss /pea /psa /pna /se etc... */ if(array_key_exists($element,$this->cur_group->fields)) { if($element == end($this->first_field)) { $this->template .= "/".$this->cur_group->name." ".$this->cur_group->name." "; $name = $this->cur_group->name; $this->cur_group = $this->cur_group->parent; $new_group = clone $this->cur_group->groups[$name]; $new_group->parent = $this->cur_group; $new_group->assign_ids($parent->main_id, $parent->id, $parent->name); $this->cur_group->group_vals[$name][] = $new_group; $this->cur_group = $new_group; unset($new_group); //unset($new_group->parent); } $this->cur_tag = $element; $this->get_val = true; $this->template .= "$element "; $found = true; } } } } } function endHandler($xp, $element) { $element = strtolower($element); //echo "END: $element \n"; if($element == $this->head_tag) { while($this->cur_group->name != $this->head_tag) { $this->template .= "/".$this->cur_group->name." "; $this->cur_group = $this->cur_group->parent; } $this->template = trim($this->template); $this->cur_group->template = $this->template; $fields = explode(" ", $this->template); $this->cur_group->destroy_subgroups(); $this->get_entry = false; } else if($this->get_entry && $this->get_val) { $this->cur_group->add_value($element,$this->cur_data); $this->get_val = false; $this->cur_tag = ""; $this->cur_data = ""; } } function cDataHandler($xp, $data) { $data = trim($data); if($this->get_val && ($data != "")) { $data = ereg_replace("&","&",$data); $data = ereg_replace("<","<",$data); $data = ereg_replace(">",">",$data); $this->cur_data .= $data; } } function check_schema() { $in = fopen($this->xml_file,"r"); while($line = fgets($in)) { xml_parse($this->parser,$line,false); } return $this->errors; } } /* $sc = new schema_checker("hierarchy.xml","test_flat_xml.xml"); $errors = $sc->check_schema(); foreach($errors as $error) { echo $error; } */ ?>