Tryag File Manager
Home
-
Turbo Force
Current Path :
/
home
/
cluster1
/
data
/
bu01
/
1121861
/
html
/
jlex
/
php4
/
Upload File :
New :
File
Dir
/home/cluster1/data/bu01/1121861/html/jlex/php4/group.php4.backup
<? /** * Group is the data structure representing XML. * * This object provides the functionality for representing XML in PHP. It is intended to serve as an intermediary * between XML and MySQL. Consequently, the 3 goals were: * <UL> * <LI>To provide functions for reading in XML into a data structure</LI> * <LI>To provide functions for writing that data structure into an SQL database.</LI> * <LI>To provide functions for retrieving the identical data associated with a given XML object.</LI> * </UL> * Because of its hierarchical nature, any data structure representing XML must necessarily * contain a lot of recursion. We will refer to any tag containing other tags as groups and and tags containinng * data as fields. A group can contain both groups and fields.<BR> * <BR> * In this implementation. Each group contains arrays containing the types of fields and groups it may contain, and * arrays containing any instances of these fields or groups. A group may contain multiple versions of the same field as * well as multiple groups of the same type. Functions are provided for adding new groups, new fields as well as * instantiations of both.<BR> * <BR> * An id system is used to maintain the relationships between elements within an XML object. * Every group, with the exception of the root, has a parent group.<BR> * Each group has an ID, a parent ID, and a main ID. The ids do not exist as part of the XML being representing but are * meta fields used by this implementation to keep track of the relationships between groups. * <UL> * <LI> The id is unique to that group. Thus no two groups of the same name have the same id.</LI> * <LI> The parent id is the id of the group for which this group is a subgroup. It provides a mechanism * for associated subgroups with their parents. The parent id consists of parent-group-name_parent-group-id.</LI> * <LI> The main id is the id of the top most group within the XML structure being represented. This provides an easy * way of retrieving an entire XML group when a member withing that group contains the content of a query. For * example, if a field is found to match a query, the main id of the group containing that field will be retrieved. * From there, all rows containing the same main id will be retrieved and eventually put into a group data * structure which will represent the entire XML group for which that field was originally part.</LI> * </UL> * For the discussion below, the following XML string will be used as the model:<BR> * <HEADGROUP><BR> * <FIELD1>value</FIELD1><BR> * <SUBGROUP1><BR> * <FIELD2>value</FIELD2><BR> * </SUBGROUP1><BR> * </HEADGROUP><BR> * <BR> * Each group will be converted into an SQL table. The table will contain a column for each field within that group. * A dilemma arises because a group may contain more than one instantiation of a particular field. There are two solutions * to this problem: * <UL> * <LI>Create one column in the table for each field. Concatenate multiple instantiations together and place them * in the same row seperated by special characters. In the original implemenation this was the route taken. However * the problem for searching is now moved to the regular expressions within queries. Since a column will contain * multiple values of a given field, the regular expression needs to be modified to deal with this as well as with * the special characters seperating the values. This puts pressure on the user to come up with clever regular * expressions, a task I found overly complex. Consequentely I decided to go the second route. * </LI> * <LI>Create one column in the table for each instantiation of a field. This requires the number of instantations to be * known beforehand. The XML data structures that I have been dealing with normally don't change over time. I have * created this version of JLex to utilize schemas (in XML) representing the largest possible XML structure possible * for a given XML document composed of many entries. An entry is the XML representing the primary repeatable * element. The schema is then used to determine the generic XML data structure for which any particular entry * could "fit" within. If new XML data structures are constantly being * created for a given project, i.e. one's differing from the generic schema, this solution does not work very well. * Currently, no functions exist allowing * the representation of an XML structure to be modified upon the upload of an XML object which exceeds the capacity * of the current schema. The flip side though is that it simplifies queries to the database. The functionality * exists such that a user provides a set of fields, a regular expression and a table and the query is constructed * to search all columns for each field provided. * </LI> * </UL> * * @package JLex */ class group { /**#@+ * @access public */ /** * The name of this group element. This is taken from the tag itself. * * In the example above, the first group will have the value "HEADGROUP". However, typically, I convert * all tags to lower case prior using them. In hierarchy_discoverer, I will first convert the tags to lowercase * and then create a new group or field based on the lowercase name. * @var string */ var $name; /** * An array containing the field-value pairs contained by this group. * * This is an associative array indexed by field name. The value contained is the number of times the group * with the most instantiations of that field has that field. This information is used when creating an * SQL table representing the current group. A new column will be created in the table representing the current * group for each field type existing. For a more complete discussion of this see above. * @var array */ var $fields; /** * The array containing instantiations of a field. * * This is an associative array indexed by field name and containing arrays of the values for the given field name. * @var array */ var $field_vals; /** * An array containing references to the groups that this group may contain as subgroups. * * The objects within this array below to the group class. The primary reason I created this implementation * was to allow for easy reloading of an XML structure from a flat structure. By obeying the requirments of * of this and the $fields array, it is umambiguous to determine whether a current field=value pair * belongs to the current group, it's parent or its child.<BR> * To create a new group value, one would clone the relevant object from this array, and place the copy * in the $group_vals array. * * @var array */ var $groups; /** * The array containing the instantitations of (sub)groups for this group. * * Note that the groups within this array should have values in either/both of $field_vals and $group_vals. In other * words, these instantiations should not simple be the models should have data as well. * @var array */ var $group_vals; /** * This is the primary wrapper tag enclosing each entry to be added to the database. It is used to identify * exactly which parts of the XML document are to be added as rows to the database. * @var string */ var $head_tag; /** * The id of this group. This should only have a value in the instantiated version of a group. * * An id is only assigned to an instance of a group. I use instance not to refer to the instantiation of a * group object but to when a group object contains data. * @var integer */ var $id; /** * The id of the "main group" which this group belongs to. * * The main group is the upper most group in an xml structure, i.e. the group that is not part of another group. * I use this id to facilitate searches. Every table created for subgroups (not the main group) in the mysql * database will contain a "main_id" column. When searching subgroup tables, I return the main_id. * I then use the set of main_ids to produce a complete result set. It is not always the case that a * complete result set is desired. For example, if a query returns hundreds of hits, you may not want to * return the full xml structure for each. The main_id provides an easy way for then going back and querying * the database for those rows that matched the original query. * @var integer */ var $main_id; /** * The id of the parent to which this group belongs. * * The parent id is always a groupname_id. To if a group belongs to the "customer" group with $id=4. * The parent_id for this group will be "customer_4". The parent_id is used for maintaining the relationships * between groups and their children groups. * * @var integer */ var $parent_id; /** * This array contains the next available id for each table that belongs to this project. * * This is an associative array indexed by group name containing integers. * @var array */ var $ids; /** * This variable points to the parent group of this group. If this is top level group, $parent is set to false. * * @var group */ var $parent; /** * The template tracks the fields and subgroups for a particular group. * * I created this in order to track the exact order of an xml structure. It is then used to * put together the XML structure in the exact order it was originally inputted into the database. * Therefore (though not recommended), if you want to rely on the order of an xml structure, * you are assured that the order will be the same. <BR> * Note that fields and the start tag opening a group are entered by name. The end tag of a group will have a slash * in it. Also, the main group will not be included in the template, but is assumed. So for the xml structure above * the template will be: <BR> * field1 subgroup1 field2 /subgroup2<BR> * Note that this field is not important if the exact xml structure does not need to be replaced. It is used * by the function to_xml_3 which uses the template to build the template. If to_xml used to reproduce the xml * the output will be in order of how fields are ordered in the $field_vals and $group_vals arrays. * * @var string */ var $template = ""; /**#@-*/ function group($name, &$ids, &$parent) { $this->name = $name; $this->ids = &$ids; $this->parent = &$parent; $this->fields = array(); $this->field_vals = array(); $this->groups = array(); $this->group_vals = array(); } /** * This is a recursive function which initializes the ids array. * * The function first sets the index for this group to 0 in the ids array. It then calls the function * for each of its subgroups. */ function init_ids() { $this->ids[$this->name] = 1; foreach($this->groups as $group) { if(!array_key_exists($group->name,$this->ids)) { $group->init_ids(); } } } /** * This function adds a field to the $fields array. It is used for building the template structure of an XML * structure. * * To add a field, the name of the field and the maximum number of times it can occur in any particular entry * is provided. * * @param string $field The name of the field to be added. * @param integer $count The maximum number of times this field can occur in a particular entry. */ function add_field($field,$count) { $this->fields[$field] = $count; } /** * This function adds a group to the $groups array. Is is used for building the template structur of an XML structure. * * Note that groups are added by reference. * @param group $group The group to be added to $groups. */ function add_group(&$group) { $this->groups[$group->name] = &$group; } /** * has_value returns true if this group contains a field in the $field_vals array, i.e. the group has a field * with a non-empty string. * * @param string $field The field being searched for. */ function has_value($field) { return (array_key_exists($field,$this->field_vals)); } /** * assign_ids assigns the relevant ids for this group object. * * This fucntion should be used to assign ids to a group rather than directly accessing the variables themselves. * @param integer $main_id The main_id belonging to the group containing this group. * @param integer $parent_id The id of the parent group to which this group belongs. * @param string $parent_name The name of the parent group to which this group belongs. */ function assign_ids($main_id, $parent_id, $parent_name) { $this->main_id = $main_id; $this->parent_id = $parent_id."_".$parent_name; $this->id = $this->ids[$this->name]; $this->ids[$this->name]++; } /** * add_value adds a field=value pair to the $field_vals array. * * @param string $field The field name being added. * @param string $value The value for the specified field. * * @return boolean False is returned if the field does not exist in the $fields array. */ function add_value($field,$value) { if(array_key_exists($field,$this->fields)) { $this->field_vals[$field][] = $value; return true; } else { return false; } } /** * Adds a group to $group_vals and sets the parent of the child group to this. * * @param group $group The group to be added. */ function add_group_value(&$group) { $this->group_vals[$group->name][] = &$group; $group->parent = &$this; } /** * Returns an array of all the names of the groups contained within this group object. * * @return array An array containing the names of all the groups contained in this object. */ function get_group_names() { $names = array($this->name); foreach($this->groups as $group) { $subgroup_names = $group->get_group_names(); foreach($subgroup_names as $name) { if(!in_array($name,$names)) { $names[] = $name; } } } return $names; } /** * A useful debugging function which prints out template information for this group. * * This function is useful for showing the template of a group. It prints to general out. */ function print_group_info() { echo "<B>Group: $this->name </B> main id: $this->main_id; parent_id: $this->parent_id;"; echo " id: this->id \n"; foreach($this->fields as $field=>$count) { echo "field: $field count: $count\n"; } foreach($this->groups as $group) { echo "group: $group->name : XX fields : ".count($group->groups)." groups \n"; } foreach($this->groups as $group) { $group->print_group_info(); } } /** * This functions prints out the values of given group (not the template). * * This is useful for seeing what currently exists in a given group. */ function print_group_values() { foreach($this->fields as $field=>$count) { if(array_key_exists($field,$this->field_vals)) { foreach($this->field_vals[$field] as $val) { echo "\\$field $val \n"; } } } foreach($this->groups as $group) { if(array_key_exists($group->name, $this->group_vals)) { foreach($this->group_vals[$group->name] as $g) { $g->print_group_values(); } } } } /** * load_query_result loads all data for a given xml structure from the set of rows corresponding to different * subgroups within the MySQL database. * * Any row within a given table contains only the values of fields for a particular group. In other words, * it does not contain any data for subgroups of the current group. This function first loads all field data. * It then determines the subgroups in the following way: * <UL> * <LI>Determine the parent id of the current group. The parent group is the groupname_id. So if the current * group is "customer" and has id "4", all of its children will have a parent id of "customer_4".</LI> * <LI>The elements in the $data array are indexed by the following convention: [parent_id]_[child-group-name]. * For example, if the "customer" group with id 4 has an "address" group, this field values for this * group will be indexed by "customer_4_address". Remember that a group may have multiple subgroups of * different types. If we only used "customer_4" to index subgroups, we would not be able to determine * what type of group the child is. By including the name in the indexing function, we know exactly * what type of group this row of data belongs to and we know which group is it's parent.</LI> * <LI>Loop through the group names that this group can have as children. Check to see if any rows * exist in the data array with the relevant index of "[parent_id]_[child-group-name]". If a row does * exist, recursively call the load_query_result function with this row as one of the arguments. This will * successfully load all the subgroups of an XML structure.</LI> * </UL> * The caveat with this implementation is that the XML structure must be known before a group can be loaded. A schema * must therefore exist describing the allowable XML structures. However, because this is data that is being loaded * from the database, it was (necessarily) first inputted into the database. Therefore, it is always the case * that we know schema at this point in the processing. * * @param array $row The fields, indexed by column name, of data for a given group. Note that all columns in all * MySQL tables are indexed numerically. So "field" become "field_0", "field_1", "field_n". This * last "_n" is removed before calling the add_field() function. * @param array $data This array is indexed by "[parent_id]_[child-group-name]" and contains arrays corresponding to * rows in an MySQL table. * @return void This group object will be filled with data following a call to this function. */ function load_query_result($row,$data) { foreach($row as $field=>$val) { if($field == "template") { $group_names = $this->get_group_names(); $cols = explode(" ",$val); foreach($cols as $col) { $c = str_replace("/","",$col); if($this->contains_field($col) || in_array($c,$group_names)) { $template .= $col." "; } } $this->template = $template; } else if((trim($val) != "") && !ereg("_id",$field)) { $val = ereg_replace("&","&",$val); $index = strrpos($field,"_"); if($index) { $field = substr($field,0,$index); } if($this->add_value($field,$val)) { //echo "parent: ".$this->parent->name." : $this->name : $field=$val<BR>"; } } } $id = $row[$this->name."_id"]."_".$this->name; foreach($this->groups as $group) { if(array_key_exists($id."_".$group->name, $data)) { foreach($data[$id."_".$group->name] as $row) { $new_group = $group; $new_group->id = $row[$group->name."_id"]; $new_group->load_query_result($row,$data); $this->group_vals[$new_group->name][] = &$new_group; unset($new_group); } } } } /** * complete_destroy explicitly destroys all the references contained by variables in this group object. * * I don't believe I ever used this function as it destroys too much. It destroys the references contained * by the groups within the $groups array which I think screws everything up. Don't use this function unless * you thoroughly test out its consequences. The function destroy_subgroups() should be sufficient. */ function complete_destroy() { unset($this->parent); $this->parent = NULL; unset($this->field_vals); $this->field_vals = NULL; $names = array_keys($this->groups); foreach($names as $name) { $g = &$this->groups[$name]; $g->destroy_subgroups(); } $names = array_keys($this->group_vals); foreach($names as $name) { $num = count($this->group_vals[$name]); for($i=0;$i<$num;$i++) { $g = &$this->group_vals[$name][$i]; $g->destroy_subgroups(); } } } /** * destroy_subgroups derefences all variables in this group and this group's subgroups. * * This function is required in PHP4. Because of the way PHP4 handles references, letting its trash collecting * system failed to eliminate many of the objects that got created. The consequence was that loading a large * XML file quickly caused a memory shortage and the program to eventually crash (depending on the memory allocation * amount set in the PHP.ini script.<BR> * Specifically, even if an object was unset, if that object maintained a reference to another object via the $parent * variable, the parent object continued to exist, even if the parent was explicitly destroyed. For example, * A has a pointer to B. If A is unset and B is unset, B will continue to exist in memory unless the pointer in A is * explicitly unset. I do not know why this occurs or why the PHP guys chose this implementation. But, it is no longer * an issue in PHP5. That is, if A and B are both unset, one does not need to explicilty unset any pointers in A to B * in order for B to be removed from memory. */ function destroy_subgroups() { unset($this->parent); $this->parent = NULL; unset($this->field_vals); $this->field_vals = NULL; if(is_array($this->group_vals)) { $names = array_keys($this->group_vals); foreach($names as $name) { $num = count($this->group_vals[$name]); for($i=0;$i<$num;$i++) { $g = &$this->group_vals[$name][$i]; $g->destroy_subgroups(); } } } $this->group_vals = NULL; $this->template = ""; } /** * This function destroys all values in the $field_vals and $group_vals array. * * Originally, I believed this function was sufficient for removing an object from memory. However as discussed in * the destroy_subgroups documentatation, this is not the case. This function still is useful for simply * removing the values of an object. */ function reset_values() { unset($this->field_vals); $this->field_vals = array(); unset($this->group_vals); $this->group_vals = array(); $this->template = ""; } /** * A function to remove html encodings of special characters. */ function unhtmlentities($string) { $trans_tbl = get_html_translation_table(HTML_ENTITIES); $trans_tbl = array_flip($trans_tbl); return strtr($string, $trans_tbl); } /** * to_ssv puts all the data for a given group into a two dimensional array indexed by group name containing * the rows corresponding to each group for an XML structure. * * The $head_tag is required as an argument because the head group (that indicated by the head tag) is slightly * different than subgroups. Namely, the head group only has a single id, whereas subgroups have 3 ids. The main * group also has a template (see discussion of the template variable). <BR> * Note that this data will eventually be put into file to be uploaded using the MySQL "LOAD" command. The load * command requires that every single column of a row be represented in the file containing the data to be uploaded. * Therefore, columnns which are empty for a particular row are still included but are empty strings. Therefore, * the array being built for a particular row will contain a value for every column (and will be the empty string * when there is no value). Here is how this is handled: * <UL> * <LI>Say given field has three columns associated with it for a particular table, e.g. field_0, field_1, field_2. * </LI> * <LI>A particular group though only has a value for field_0. $row[field][0] = value and $row[field][1] = '' * and $row[$field][2] = "".</LI> * </UL> * Each row will then be imploded into a single string using the '^' character to enclose data and each piece of * data seperated by a space. This string will then be entered into the $result array, which is indexed by * groupname and contains an array of strings.<BR> * Next, we must cycle through the subgroups of this group. This function is called rescursively for each * instance of a subgroup. to_ssv returns an array of arrays indexed by group name containing arrays of rows. * The result of the recursively called function is then added to the result of the object making the * recursive call. The finall result will be an array indexed by group name containing arrays of rows. Note * that the nested structure of subgroups is flattened here. It does not matter for the purposes of * inputting this data into the SQL database the relationship between one row and another. This informaiton * is maintained via the parent_id. Evententually, there will be a seperate file created for each unique table * of a project containing properly formatted (enclosed by the ^ symbol and space seperated) lines corresponding * to future rows of the table. * * @param string $head_tag The outermost tag of the XML structure. * @return array An array of arrays indexed by group name containing an array of rows. */ function to_ssv($head_tag) { $row = array(); $row[$head_tag][0] = $this->main_id; if($this->name != $head_tag) { $row["parent_id"][0] = $this->parent_id; $row["id"][0] = $this->id; } else { $row["template"][] = $this->template; } foreach($this->fields as $field=>$count) { if(array_key_exists($field,$this->field_vals)) { foreach($this->field_vals[$field] as $val) { $val = $this->unhtmlentities($val); $row[$field][] = $val; } $num_fields = count($this->field_vals[$field]); for($i=$num_fields;$i<$count;$i++) { $row[$field][$i] = ""; } } else { for($i=0; $i<$count;$i++) { $row[$field][$i] = ""; } } } $s = ""; foreach($row as $field=>$vals) { foreach($vals as $val) { $s .= "^$val^ "; } } $result[$this->name][] = $s; if($this->group_vals != null) { foreach($this->groups as $group) { if(array_key_exists($group->name, $this->group_vals)) { foreach($this->group_vals[$group->name] as $g) { //echo "adding ".$g->name."<BR>"; $subgroup_tabledata = $g->to_ssv($head_tag); foreach($subgroup_tabledata as $table=>$rows) { foreach($rows as $row) { $result[$table][] = $row; } } } } } } return $result; } /** * This returns an array of all groups containing $field. * * The array is ordered in key-value pairs of group_name=count where count is * the amount of fields which may exist in that group. For example, * if a group can have up to 3 lxa fields, the count is 3. * @param $field The field being looked up. * @return array The array is indexed by group name and contains the maximum number of fields allowed for that group. */ function find_group($field) { $group_names = array(); if(array_key_exists($field,$this->fields) ) { $group_names[$this->name] = $this->fields[$field]; } foreach($this->groups as $group) { $subgroup_names = $group->find_group($field); foreach($subgroup_names as $name=>$count) { if(!array_key_exists($name,$group_names)) { $group_names[$name] = $count; } } } return $group_names; } /** * I think this function was intended to produce dynnamically generated code for making an multi-dimensional array * equivalent in size to the group structure. I don't believe it's been tested. */ function make_tables_array(&$tables) { $s = "\"$this->name\" => array("; foreach($this->fields as $field=>$count) { $s .= "\"$field\"=>$count,"; } $s = substr($s,0,-1).")"; $tables[$this->name] = $s; foreach($this->groups as $group) { if(!array_key_exists($group->name, $tables)) { $group->make_tables_array(&$tables); } } } /** * to_xml produces an xml string containing all the information (not ids) contained in this group structure. * * This function though does not maintain the original ordering of the XML structure when it was first loaded * into the database. Rather, first the fields are printed out in order that they were inputted into the $field_vals * array. Second, the groups are printed out in order that they exist in the $groups (not $group_vals) array. */ function to_xml() { $xml = "<$this->name>\n"; foreach($this->field_vals as $field=>$vals) { foreach($vals as $val) { if(trim($val) != "") { $xml .= "<$field>$val</$field>\n"; } } } foreach($this->groups as $group) { if(array_key_exists($group->name, $this->group_vals)) { foreach($this->group_vals[$group->name] as $g) { $xml .= $g->to_xml(); } } } $xml .= "</$this->name>\n"; return $xml; } /** * to_xml_3 prints out the XML structure of this group in the exact order it was originally inputted into MySQL. * In addition, the option to print with ids may be provided. * * This function requires a template to dictate the ordering of the XML. The template must obey the following rules: * <UL> * <LI> The template constists of space seperated tokens.</LI> * <LI> The head group is not part of the template.</LI> * <LI> To indicate the start of a subgroup, the subgroup name is added to the template.</LI> * <LI> To indicate the end of a subgroup, the subgroup name preceded by a forward slash is added to the template, * e.g. /subgroup.</LI> * <LI> To indicate a field, add the field name to the template.</LI> * </UL> * If an error is encountered with the template, i.e. a token is encountered which is invalid, the function will quit. * Errors include fields which are not part of the current subgroup, the start of subgroups which do not exist in the * current group, the end of a subgroup which is not the current group.<BR> * If $with_ids parameter is set to true, the XML structure will include the id of the current group though * not the parent or main id. * * @param string $template A space seperated string of the fields and subgroups describing the ordering of the * current group. * @param boolean $with_ids When set to true, the group id will be included in the XML structure being output. * @return string The XML structure of this group. */ function to_xml_3($template, $with_ids) { $xml = "<$this->name>\n"; if($with_ids) { $xml .= "<".$this->name."_id>$this->id</".$this->name."_id>\n"; } $indices = array(); while(count($template) != 0) { $cur_tag = array_shift($template); if(!array_key_exists($cur_tag,$indices)) { $indices[$cur_tag] = 0; } $index = $indices[$cur_tag]; $indices[$cur_tag]++; if(array_key_exists($cur_tag,$this->fields)) { if(array_key_exists($cur_tag,$this->field_vals)) { $val = $this->field_vals[$cur_tag][$index]; } else { $val = ""; } $xml .= "<$cur_tag>$val</$cur_tag>\n"; } else if(array_key_exists($cur_tag,$this->group_vals)){ $group = $this->group_vals[$cur_tag][$index]; $subgroup_template = array(); while(($cur_tag = array_shift($template)) != "/".$group->name) { $subgroup_template[] = $cur_tag; } $xml .= $group->to_xml_3($subgroup_template,$with_ids); } else { echo "No $cur_tag group within this group object \n"; die("Error!"); } } $xml .= "</$this->name>\n"; return $xml; } /** * contains_field returns true if this group or any of its subgroups contains the field. * * Note that this does not search for whether a subgroup contains a value for the given field. Only * whether the group or a subgroup contains the field in the $fields array. has_value should * be used to determine if the current group contains a value for a given field. However, that function * only searches the current group but not any subgroups. Furthermore, the function * only searches down the tree, but not up it. * * @param string $field The field being search for. * @return boolean True if this group or any subgroup contains the field. */ function contains_field($field) { if(array_key_exists($field,$this->fields)) { return true; } else { foreach($this->groups as $group) { $result = $group->contains_field($field); if($result) { return true; } } } return false; } /** * This function produces the schema for the group. * * A schema has the following format:<BR> * <group name="name"><BR> * <field count="X">field-name</field><BR> * <group name="name"><BR> * <field count="X">field-name</field><BR> * </group><BR> * </group><BR> * The schema is used to create the group structure representing allowable XML structures. Please see the * documentation for the hierarchy_loader class to understand how this is accomplished. * @return string A string in XML of the schema representing this group. */ function structure_to_xml() { $xml = "<group name=\"$this->name\">\n"; ksort($this->fields); foreach($this->fields as $field=>$count) { $xml .= "<field count=\"$count\">$field</field>\n"; } foreach($this->groups as $group) { $xml .= $group->structure_to_xml(); } $xml .= "</group>\n"; return $xml; } /** * write_schema writes to disk, under the provided file name, the schema for this group. * * @param string $file_name The name of the file written to disk. */ function write_schema($file_name) { $out = fopen($file_name,"w"); fwrite($out,$this->structure_to_xml()); fclose($out); } /** * This function sets the $parent variable in each of the groups in the $groups array to this group. * * I don't know if this function is ever used or why exactly I wrote it in the first place. */ function set_parent() { $names = array_keys($this->groups); foreach($names as $name) { $g = &$this->groups[$name]; //echo "setting $g->name \n"; $g->parent = &$this; $g->set_parent(); } } /** * get_field_names returns an array sorted alphabetically of all the fields in this group and all of its * subgroups. * * @return array An alphabetically sorted array of all the fields in this group and all of its subgroups. */ function get_field_names() { $fields = array(); foreach($this->fields as $field=>$count) { $fields[] = $field; } foreach($this->groups as $group) { $fields = array_merge($fields,$group->get_field_names()); } $fields = array_unique($fields); sort($fields); return $fields; } } ?>