options = $options; } private function indent($path){ $depth = sizeof(explode("/", $path)) - 1; $indent=""; $indent = str_pad($indent, $depth, "\t"); return "\r\n" . $indent; } public function serialize($parent_node_name, $data, $path=""){ $xml = ""; if(empty($path)){ $path = $parent_node_name; $xml = ""; } //if this element is marked as hidden, ignore it $option = rgar($this->options, $path); if(rgar($option,"is_hidden")) return ""; $padding = $this->indent($path); //if the content is not an array, simply render the node if(!is_array($data)){ $option = rgar($this->options,$path); return strlen($data) == 0 && !rgar($option, "allow_empty") ? "" : "$padding<$parent_node_name>" . $this->xml_value($parent_node_name, $data) . ""; } $is_associative = $this->is_assoc($data); $is_empty = true; //opening parent node $version = $path == $parent_node_name && isset($this->options["version"]) ? " version=\"" . $this->options["version"] . "\"" : ""; $xml .= "{$padding}<{$parent_node_name}{$version}"; if($is_associative){ //adding properties marked as attributes for associative arrays foreach($data as $key => $obj){ $child_path = "$path/$key"; if($this->is_attribute($child_path)){ $value = $this->xml_attribute($obj); $option = rgar($this->options, $child_path); if(strlen($value) > 0 || rgar($option, "allow_empty")){ $xml .= " $key=\"$value\""; $is_empty = false; } } } } //closing element start tag $xml .= ">"; //for a regular array, the child element (if not specified in the options) will be the singular vesion of the parent element(i.e.
...
...
) $child_node_name = isset($this->options[$path]["array_tag"]) ? $this->options[$path]["array_tag"] : $this->to_singular($parent_node_name); //adding other properties as elements foreach($data as $key => $obj){ $node_name = $is_associative ? $key : $child_node_name; $child_path = "$path/$node_name"; if(!$this->is_attribute($child_path)){ $child_xml = $this->serialize($node_name, $obj, $child_path); if(strlen($child_xml) > 0){ $xml .= $child_xml; $is_empty = false; } } } //closing parent node $xml .= "$padding"; return $is_empty ? "" : $xml; } public function unserialize($xml_string){ $xml_string = trim($xml_string); $xml_parser = xml_parser_create(); $values = array(); xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, false); xml_parser_set_option($xml_parser, XML_OPTION_SKIP_WHITE, 1); xml_parse_into_struct($xml_parser, $xml_string, $values); $object = $this->unserialize_node($values, 0); xml_parser_free($xml_parser); return $object; } private function unserialize_node($values, $index){ $current = $values[$index]; //initializing current object $obj = array(); //each attribute becomes a property of the object if(isset($current["attributes"]) && is_array($current["attributes"])){ foreach($current["attributes"] as $key => $attribute) $obj[$key] = $attribute; } //for nodes without children(i.e. contact us or ), simply return its content if($current["type"] == "complete"){ $val = isset($current["value"]) ? $current["value"] : ""; return !empty($obj) ? $obj : $val; } //get the current node's immediate children $children = $this->get_children($values, $index); if(is_array($children)){ //if all children have the same tag, add them as regular array items (not associative) $is_identical_tags = $this->has_identical_tags($children); $unserialize_as_array = $is_identical_tags && isset($this->options[$children[0]["tag"]]) && $this->options[$children[0]["tag"]]["unserialize_as_array"]; //serialize every child and add it to the object (as a regular array item, or as an associative array entry) foreach($children as $child){ $child_obj = $this->unserialize_node($values, $child["index"]); if($unserialize_as_array) $obj[] = $child_obj; else $obj[$child["tag"]] = $child_obj; } } return $obj; } private function get_children($values, $parent_index){ $level = $values[$parent_index]["level"] + 1; $nodes = array(); for($i= $parent_index + 1, $count = sizeof($values); $i<$count; $i++){ $current = $values[$i]; //If we have reached the close tag for the parent node, we are done. Return the current nodes. if($current["level"] == $level -1 && $current["type"] == "close") return $nodes; else if($current["level"] == $level && ($current["type"] == "open" || $current["type"] == "complete")) $nodes[] = array("tag" => $current["tag"], "index" => $i); //this is a child, add it to the list of nodes } return $nodes; } private function has_identical_tags($nodes){ $tag = $nodes[0]["tag"]; foreach($nodes as $node){ if($node["tag"] != $tag) return false; } return true; } private function is_attribute($path){ $option = rgar($this->options, $path); return rgar($option,"is_attribute"); } private function xml_value($node_name, $value){ if(strlen($value) == 0) return ""; if($this->xml_is_cdata($node_name)) return $this->xml_cdata($value); else return $this->xml_content($value); } private function xml_attribute($value){ return esc_attr($value); } private function xml_cdata($value){ return ""; } private function xml_content($value){ return $value; } private function xml_is_cdata($node_name){ return true; } private function is_assoc($array){ return is_array($array) && array_diff_key($array,array_keys(array_keys($array))); } private function to_singular($str){ $last3 = strtolower(substr($str, strlen($str) - 3)); $fourth = strtolower(substr($str, strlen($str) - 4, 1)); if( $last3 == "ies" && in_array($fourth, array("a","e","i","o","u") ) ){ return substr($str, 0, strlen($str)-3) . "y"; } else{ return substr($str, 0, strlen($str)-1); } } } if(!function_exists("rgar")){ function rgar($array, $name){ if(isset($array[$name])) return $array[$name]; return ''; } } ?>