clibxml2xmlwriterxmltextwriter

C libxml2 xmlTextWriter tags nest themselves randomly


I have a struct that I am trying to save as an xml, it seems to have no problems with creating small XMLs, however in the case of larger files it seems to nest the later tags, for the first 30 or so I am getting correct results in the format:

<argument><kind>2</kind><string>video.avi</string></argument><argument><kind>4</kind><string>0</string></argument>

However, after a while things start going in the format:

<argument><kind>5</kind><string/><argument><kind>2</kind><string>sprite.gif</string></argument></argument>

Which is incorrect, the arguments shouldn't be nested.

//Save an obiect as in xml/gm format
int save_obj(struct gm_object obj, char *file_str)
{
  xmlTextWriterPtr writer;
  xmlChar *tmp;
  // Create a new XmlWriter for uri, with no compression.
  writer = xmlNewTextWriterFilename(file_str, 0);
  if (writer == NULL)
  {
    return 1; //1 = error
  }
  xmlTextWriterStartDocument(writer, NULL, "UTF-8", "no");
  //Root
  xmlTextWriterStartElement(writer, BAD_CAST "object");
  xmlTextWriterWriteElement(writer, BAD_CAST "spriteName", BAD_CAST obj.spriteName);
  xmlTextWriterWriteFormatElement(writer, BAD_CAST "solid","%i",obj.solid);
  xmlTextWriterWriteFormatElement(writer, BAD_CAST "visible","%i",obj.visible);
  xmlTextWriterWriteFormatElement(writer, BAD_CAST "depth","%i",obj.depth);
  xmlTextWriterWriteFormatElement(writer, BAD_CAST "persistent","%i",obj.persistent);
  xmlTextWriterWriteElement(writer, BAD_CAST "maskName", BAD_CAST obj.maskName);
  xmlTextWriterWriteElement(writer, BAD_CAST "parentName", BAD_CAST obj.parentName);
  xmlTextWriterStartElement(writer, BAD_CAST "events");
  //This is where we store any ints that need to be converted to strings
  char str_int_converted[(CHAR_BIT * sizeof(int) - 1) / 3 + 2];
  int i;
  for (i = 0; i<obj.event_count-1;i++)
  {
    xmlTextWriterStartElement(writer, BAD_CAST "event");
    sprintf(str_int_converted, "%d", obj.events[i].enumb);
    xmlTextWriterWriteAttribute(writer, BAD_CAST "enumb", BAD_CAST str_int_converted);
    sprintf(str_int_converted, "%d", obj.events[i].eventtype);
    xmlTextWriterWriteAttribute(writer, BAD_CAST "eventtype", BAD_CAST str_int_converted);
    int ii;
    for (ii = 0; ii<obj.events[i].action_count-1;ii++)
    {
      xmlTextWriterStartElement(writer, BAD_CAST "action");
      xmlTextWriterWriteFormatElement(writer, BAD_CAST "libid", "%i", obj.events[i].actions[ii].libid);
      xmlTextWriterWriteFormatElement(writer, BAD_CAST "id","%i", obj.events[i].actions[ii].id);
      xmlTextWriterWriteFormatElement(writer, BAD_CAST "kind","%i", obj.events[i].actions[ii].kind);
      xmlTextWriterWriteFormatElement(writer, BAD_CAST "userelative","%i", obj.events[i].actions[ii].userelative);
      xmlTextWriterWriteFormatElement(writer, BAD_CAST "useapplyto", "%i", obj.events[i].actions[ii].useapplyto);
      xmlTextWriterWriteFormatElement(writer, BAD_CAST "isquestion", "%i", obj.events[i].actions[ii].isquestion);
      xmlTextWriterWriteFormatElement(writer, BAD_CAST "exetype","%i", obj.events[i].actions[ii].exetype);
      xmlTextWriterWriteElement(writer, BAD_CAST "functionname", BAD_CAST obj.events[i].actions[ii].functionname);
      xmlTextWriterWriteElement(writer, BAD_CAST "codestring", BAD_CAST obj.events[i].actions[ii].codestring);
      xmlTextWriterWriteElement(writer, BAD_CAST "whoName", BAD_CAST obj.events[i].actions[ii].whoName);
      xmlTextWriterWriteFormatElement(writer, BAD_CAST "relative","%i", obj.events[i].actions[ii].relative);
      xmlTextWriterWriteFormatElement(writer, BAD_CAST "isnot","%i", obj.events[i].actions[ii].isnot);
      xmlTextWriterStartElement(writer, BAD_CAST "arguments");
      int iii;
      for (iii = 0; iii<obj.events[i].actions[ii].arg_count-1;iii++)
      {
        //causing some of these to nest rather than properly close
        xmlTextWriterStartElement(writer, BAD_CAST "argument");
        xmlTextWriterWriteFormatElement(writer, BAD_CAST "kind", "%i", obj.events[i].actions[ii].arguments[iii].kind);
        xmlTextWriterWriteElement(writer, BAD_CAST "string", obj.events[i].actions[ii].arguments[iii].string);
        xmlTextWriterEndElement(writer); //Close <argument>
      }
      xmlTextWriterEndElement(writer); //Close <arguments>
      xmlTextWriterEndElement(writer); //Close <action>
    }
    xmlTextWriterEndElement(writer); //Close <event>
  }
  xmlTextWriterEndElement(writer); //Close <events>
  //Put physics stuff here
  xmlTextWriterWriteFormatElement(writer, BAD_CAST "PhysicsObject","%i", obj.PhysicsObject);
  xmlTextWriterWriteFormatElement(writer, BAD_CAST "PhysicsObjectSensor","%i", obj.PhysicsObjectSensor);
  xmlTextWriterWriteFormatElement(writer, BAD_CAST "PhysicsObjectShape","%i", obj.PhysicsObjectShape);
  xmlTextWriterWriteFormatElement(writer, BAD_CAST "PhysicsObjectDensity","%f", obj.PhysicsObjectDensity);
  xmlTextWriterWriteFormatElement(writer, BAD_CAST "PhysicsObjectRestitution","%f", obj.PhysicsObjectRestitution);
  xmlTextWriterWriteFormatElement(writer, BAD_CAST "PhysicsObjectGroup","%i", obj.PhysicsObjectGroup);
  xmlTextWriterWriteFormatElement(writer, BAD_CAST "PhysicsObjectLinearDamping","%f", obj.PhysicsObjectLinearDamping);
  xmlTextWriterWriteFormatElement(writer, BAD_CAST "PhysicsObjectAngularDamping","%f", obj.PhysicsObjectAngularDamping);
  xmlTextWriterWriteFormatElement(writer, BAD_CAST "PhysicsObjectFriction","%f", obj.PhysicsObjectFriction);
  xmlTextWriterWriteFormatElement(writer, BAD_CAST "PhysicsObjectAwake","%i", obj.PhysicsObjectAwake);
  xmlTextWriterWriteFormatElement(writer, BAD_CAST "PhysicsObjectKinematic","%i", obj.PhysicsObjectKinematic);
  xmlTextWriterStartElement(writer, BAD_CAST "PhysicsShapePoints");
  //This is where we store any floats that need to be converted to strings
  char str_float_converted[(CHAR_BIT * sizeof(float) - 1) / 3 + 2];
  for (i=0;i<obj.point_count;i++)
  {
    xmlTextWriterWriteFormatElement(writer, BAD_CAST "point","%i,%i", obj.PhysicsShapePoints[i].x, obj.PhysicsShapePoints[i].y);
  }
  xmlTextWriterEndElement(writer); //Close <PhysicsShapePoints>
  xmlTextWriterEndDocument(writer);
  xmlFreeTextWriter(writer);
}

Here is the full file it's producing: http://pastebin.com/raw/iJHYWkWq Sorry I was unable to put it in the body of this post because it went over the character limit. I would be very grateful for any help, I've been working at this bug for 4 hours now and I can't seem to find anyone else who's had this problem let alone fixed it.


Solution

  • The xmlTextWriterWriteElement() does not work well if you pass it a NULL. Verify that your string is not NULL before calling the API or use xmlTextWriterWriteFormatElement() and %s as the format.