Handling elements: endElement

Previous: Handling elements: startElement ] [ Top: xmltools index ] [ Next: Handling non-element data: charData ]

The endElement function is called whenever expat hits the close of an element. In the event that an empty element is used (e.g. <tag name="empty"/>) then both startElement and endElement will be called, as though the XML were actually <tag name="empty"></tag>. This makes things much easier to write -- but it also means we have to do a little gyration if we want to be able to write empty tags to our output.

This is of course why we have an empty flag on each tag; if the tag is still empty, then endElement will print "/>" to close it; otherwise it will print the entire close tag, name and all.

You can see that xmlinsert checks for whether it has anything to insert, before anything else is done, and after the tag is closed. If the insertion is to an empty tag, then we have to close the tag and mark it nonempty.

And then you notice that we have three different if statements -- xmlsnip only emits the tag if it is in the snip location, xmlreplace only emits the tag if it's not being replaced, and everybody else emits the tag if tags are being emitted. Since that part is handled inside the if, the outer if is just an if (1). In retrospect that's kind of an odd way to code that; I guess it shows that I wrote xmlsnip first and then hacked it up to make the other tools.
 
void endElement(void *userData, const char *name)
{
   FRAME * old;
   int c;

#ifdef XMLINSERT
   if (top->level == emit_level && !strcmp (insertwhere, "aftercontent")) {
      if (top->empty) {
         printf (">");
         top->empty = 0;
      }
      while (!feof(stdin)) { c = getchar(); if (!feof(stdin)) putchar(c); }
      emit_level = -1;
   }
#endif

#ifdef XMLSNIP
   if (!finished && emit_level > -1 && top->level - 1 + emit_matching_tag >= emit_level) {
#else
#ifdef XMLREPLACE
   if (emit_level < 0 || top->level + emit_matching_tag <= emit_level) {
#else
   if (1) {
#endif
#endif
      if (! top->empty) {
         if (emit_tags) printf ("</%s", name);
      } else {
         if (emit_tags) printf ("/");
      }
      if (emit_tags) printf (">");
   }

#ifdef XMLINSERT
   if (top->level == emit_level && !strcmp (insertwhere, "after")) {
      while (!feof(stdin)) { c = getchar(); if (!feof(stdin)) putchar(c); }
      emit_level = -1;
   }
#endif

#ifdef XMLSNIP
   if (top->level == emit_level) finished = 1;
#endif
   if (top->level == emit_level) emit_level = -1;

   old = top;
   if (top->back->level == 0) {
      top->back->next = NULL;
   }
   top = top->back;
   free_frame (old);
}
Previous: Handling elements: startElement ] [ Top: xmltools index ] [ Next: Handling non-element data: charData ]


This code and documentation are released under the terms of the GNU license. They are additionally copyright (c) 2000, Vivtek. All rights reserved except those explicitly granted under the terms of the GNU license.