Contents Previous Next

Save Callbacks

Chapter 2 also introduced the mxmlSaveFile(), mxmlSaveString(), and mxmlSaveAllocString() functions. The last argument to these functions is a callback function which is used to automatically insert whitespace in an XML document.

Your callback function will be called up to four times for each element node with a pointer to the node and a "where" value of MXML_WS_BEFORE_OPEN, MXML_WS_AFTER_OPEN, MXML_WS_BEFORE_CLOSE, or MXML_WS_AFTER_CLOSE. The callback function should return NULL if no whitespace should be added and the string to insert (spaces, tabs, carriage returns, and newlines) otherwise.

The following whitespace callback can be used to add whitespace to XHTML output to make it more readable in a standard text editor:

    const char *
    whitespace_cb(mxml_node_t *node,
                  int where)
    {
      const char *name;

     /*
      * We can conditionally break to a new line
      * before or after any element. These are
      * just common HTML elements...
      */

      name = node->value.element.name;

      if (!strcmp(name, "html") ||
          !strcmp(name, "head") ||
          !strcmp(name, "body") ||
	  !strcmp(name, "pre") ||
          !strcmp(name, "p") ||
	  !strcmp(name, "h1") ||
          !strcmp(name, "h2") ||
          !strcmp(name, "h3") ||
	  !strcmp(name, "h4") ||
          !strcmp(name, "h5") ||
          !strcmp(name, "h6"))
      {
       /*
	* Newlines before open and after
        * close...
	*/

	if (where == MXML_WS_BEFORE_OPEN ||
            where == MXML_WS_AFTER_CLOSE)
	  return ("\n");
      }
      else if (!strcmp(name, "dl") ||
               !strcmp(name, "ol") ||
               !strcmp(name, "ul"))
      {
       /*
	* Put a newline before and after list
        * elements...
	*/

	return ("\n");
      }
      else if (!strcmp(name, "dd") ||
               !strcmp(name, "dt") ||
               !strcmp(name, "li"))
      {
       /*
	* Put a tab before <li>'s, * <dd>'s,
        * and <dt>'s, and a newline after them...
	*/

	if (where == MXML_WS_BEFORE_OPEN)
	  return ("\t");
	else if (where == MXML_WS_AFTER_CLOSE)
	  return ("\n");
      }

     /*
      * Return NULL for no added whitespace...
      */

      return (NULL);
    }

To use this callback function, simply use the name when you call any of the save functions:

    FILE *fp;
    mxml_node_t *tree;

    fp = fopen("filename.xml", "w");
    mxmlSaveFile(tree, fp, whitespace_cb);
    fclose(fp);

Contents Previous Next