/********************************************************/
/* Xml_Read_File - Example				*/
/********************************************************/
Xml_object *Xml_Read_File( char *fname )
{
 FILE *infile;
 int lnn=0;
 char *tag, *attrib, *value, *contents;
 Xml_object *newtag, *roottag=0;
 Xml_name_value_pair *newattrib, *lastattrib;
 struct xml_private_stack *current_parent, *old_tag;	/* Current_parent points to parent of current children. */


 infile = fopen(fname,"r");
 if (infile==0) {printf("XML Error: Cannot open input file '%s'.\n",fname); return 0;}
 current_parent = new_xml_stack_item(0,0);  /* Set the root tag level. */
 tag = (char *)malloc(XML_MAX_STRLEN);
 attrib = (char *)malloc(XML_MAX_STRLEN);
 value = (char *)malloc(XML_MAX_STRLEN);
 contents = (char *)malloc(XML_MAX_STRLEN);
 xml_parse( infile, tag, contents, XML_MAX_STRLEN, &lnn ); 
 while (!feof(infile))
  { /*next_tag*/
    xml_grab_tag_name( tag, attrib, XML_MAX_STRLEN ); 

    if (attrib[0]=='/')		/* If tag begins with "/", then go-up (pop-stack after comparing tag). */
     { /*pop-stack*/
       if ((current_parent->current_object==0) || (strcasecmp(current_parent->current_object->tag,&(attrib[1]))!=0))
	{printf("Xml Error: Mismatching closing tag '%s'. Aborting.\n",attrib); free(tag); free(attrib); free(value); free(contents); return 0;}
       old_tag = current_parent;
       current_parent = current_parent->parent;
       xml_private_free_stack_item( old_tag );
       if (current_parent==0)
	{printf("Xml Error: extra closing tag '%s'. Aborting.\n",attrib); free(tag); free(attrib); free(value); free(contents); return 0;}
     } /*pop-stack*/
    else
     { /*Open-tag*/
      newtag = new_xml_object( attrib, contents );
      if (roottag == 0)	roottag = newtag;
      else
       {
	if (current_parent->last_child == 0)  current_parent->current_object->children = newtag;
	else current_parent->last_child->nxt = newtag;
        newtag->parent = current_parent->current_object;
       }
      current_parent->last_child = newtag;

      xml_grab_attrib( tag, attrib, value, XML_MAX_STRLEN ); 	/* Accept the attributes within tag. */
      while ((attrib[0]!='\0') && (attrib[0]!='/') && (attrib[0]!='?'))
       {
        newattrib = new_xml_attribute( attrib, value );
        if (newtag->attributes==0) newtag->attributes = newattrib; else lastattrib->nxt = newattrib;
        lastattrib = newattrib;
	xml_grab_attrib( tag, attrib, value, XML_MAX_STRLEN ); 
       }

      /* If tag does not end in "/", then go-down (push-stack). IE. Next tag should be a child of present tag. */
      if (attrib[0]!='/')
       {
        current_parent = new_xml_stack_item( current_parent, newtag );
       }  /* Otherwise, attaches to last child of present parent. */
     } /*Open-tag*/

    xml_parse( infile, tag, contents, XML_MAX_STRLEN, &lnn ); 
  } /*next_tag*/
 fclose(infile);
 while (xml_stack_freelist != 0)	/* Cleanup temporary variables. */
  { current_parent = xml_stack_freelist;  xml_stack_freelist = xml_stack_freelist->parent;  free(current_parent); }
 free(tag);  free(attrib);  free(value);  free(contents);
 return roottag;
}