xml_sort: Sorting children

Previous: xml_charcodings: dealing with UTF-8 and systems that don't quite get it ] [ Top: index ] [ Next: xml_assemble: Putting together SOAP responses ]

(November 11, 2001): Another month, another lack. This time I want to invoke qsort on the children of an XML element. Should be easy, eh? Actually, it is pretty easy. All we do is (1) build an array of information about what we're sorting, (2) call qsort in the standard library on the array, passing it our comparison function, and (3) use the finished sorted array to rebuild the element pointers for the children. Done. Text is ignored; only elements are sorted, and for the time being the actual element name is also ignored. (Maybe that will turn out to be a bad decision.)
 
struct _xml_sort_hdl {
  XML * sort;
  XML * elem;
};
int _xml_sort_comparison (const void * a, const void * b);
XMLAPI XML * xml_sort (XML * list, XML * sort)
{
   int i;
   XML * child;
   struct _xml_sort_hdl * array;
   ELEMENTLIST * elist;

   /* Count the children. */
   i=0; child = xml_firstelem (list);
   while (child) {
      i++;
      child = xml_nextelem (child);
   }
   if (i < 2) return list;

   /* Build the array. */
   array = (struct _xml_sort_hdl *) malloc (i * sizeof (struct _xml_sort_hdl));
   i=0; child = xml_firstelem (list);
   while (child) {
      array[i].sort = sort;
      array[i].elem = child;
      i++;
      child = xml_nextelem (child);
   }

   /* Sort the array. */
   qsort (array, i, sizeof (struct _xml_sort_hdl), _xml_sort_comparison);

   /* Rearrange the children, being very slick about it. */
   i = 0; elist = list->children;
   while (elist) {
      if (elist->element->name) {
         elist->element = array[i].elem;
         i++;
      }
      elist = elist->next;
   }

   free ((void *) array);

   return list;
}
So let's do the comparison function, and we're done.
 
int _xml_sort_comparison (const void * a, const void * b)
{
   XML * sort;
   int res;
   int ia, ib;
   struct _xml_sort_hdl * _a = (struct _xml_sort_hdl *) a;
   struct _xml_sort_hdl * _b = (struct _xml_sort_hdl *) b;

   if (a == b) return 0;

   sort = _a->sort;
   while (sort) {
      if (!strcmp (xml_attrval (sort, "op"), "num")) {
         ia = xml_attrvalnum (_a->elem, xml_attrval (sort, "field"));
         ib = xml_attrvalnum (_b->elem, xml_attrval (sort, "field"));
         if (ia < ib) res = -1;
         if (ia > ib) res = 1;
      } else {
         res = strcmp (xml_attrval (_a->elem, xml_attrval (sort, "field")), xml_attrval (_b->elem, xml_attrval (sort, "field")));
      }

      if (!strcmp (xml_attrval (sort, "dir"), "desc")) res = - res;
      if (res) return res;

      sort = xml_firstelem (sort);
   }
   return 0;
}
Previous: xml_charcodings: dealing with UTF-8 and systems that don't quite get it ] [ Top: index ] [ Next: xml_assemble: Putting together SOAP responses ]


This code and documentation are released under the terms of the GNU license. They are copyright (c) 2000-2003, Vivtek. All rights reserved except those explicitly granted under the terms of the GNU license. This presentation was created using LPML.