start moving beyond PMModelItemInfo
[pspp] / parse-xml.c
index c0445052ed017f6ea80111568dc581884c69d4e1..15c4ba2e9bc1c21cb4eb4935304d8c894add1581 100644 (file)
 #include <stdio.h>
+#include <string.h>
 #include <libxml/parser.h>
 #include <libxml/tree.h>
 
 static void
-print_containment (xmlNode * a_node)
+print_parents(xmlNode *node)
 {
-  for (xmlNode *node = a_node; node; node = node->next)
+  for (; node; node = node->next)
     {
       if (node->type == XML_ELEMENT_NODE)
         {
-          const xmlNode *parent = node->parent;
-          if (parent->type == XML_ELEMENT_NODE)
-            printf ("%s %s\n", parent->name, node->name);
-          else if (parent->type == XML_DOCUMENT_NODE)
-            printf ("<root> %s\n", node->name);
+          for (xmlNode *child = node->children; child; child = child->next)
+            {
+              if (child->type == XML_ELEMENT_NODE)
+                  printf ("%s %s\n", node->name, child->name);
+              else if (child->type == XML_TEXT_NODE)
+                printf ("%s <text>\n", node->name);
+              else if (child->type == XML_CDATA_SECTION_NODE)
+                printf ("%s <cdata>\n", node->name);
+              else if (child->type == XML_COMMENT_NODE)
+                printf ("%s <comment>\n", node->name);
+              else
+                printf ("%s <%d>\n", node->name, child->type);
+            }
+        }
+
+      print_parents (node->children);
+    }
+}
+
+static void
+print_containment (xmlNode *node)
+{
+  for (; node; node = node->next)
+    {
+      if (node->type == XML_ELEMENT_NODE)
+        {
+          const char *child_names[512];
+          int child_name_cnt[512];
+          int n_names = 0;
+          for (xmlNode *child = node->children; child; child = child->next)
+            {
+              const char *name;
+
+              if (child->type == XML_ELEMENT_NODE)
+                name = (char *) child->name;
+              else if (child->type == XML_TEXT_NODE)
+                name = "<text>";
+              else if (child->type == XML_CDATA_SECTION_NODE)
+                name = "<cdata>";
+              else if (child->type == XML_COMMENT_NODE)
+                {
+                  name = "<comment>";
+                  //printf ("comment %s\n", (char *) child->content);
+                  continue;
+                }
+              else
+                name = "<other>";
+
+              for (int i = 0; i < n_names; i++)
+                if (!strcmp(name, child_names[i]))
+                  {
+                    child_name_cnt[i]++;
+                    goto next;
+                  }
+              child_names[n_names] = name;
+              child_name_cnt[n_names] = 1;
+              n_names++;
+
+            next:;
+            }
+
+          printf ("%s", node->name);
+          for (int i = 0; i < n_names; i++)
+            {
+              printf (" %s", child_names[i]);
+              if (child_name_cnt[i] > 1)
+                printf ("+");
+            }
+          printf ("\n");
         }
 
       print_containment (node->children);
     }
 }
 
-int
-main (int argc, char **argv)
+static void
+print_labels (xmlNode *node)
+{
+  for (; node; node = node->next)
+    {
+      if (node->type == XML_ELEMENT_NODE
+          && !strcmp((char *) node->name, "label")
+          && node->parent->type == XML_ELEMENT_NODE
+          && !strcmp((char *) node->parent->name, "container"))
+        {
+          for (xmlNode *child = node->children; child; child = child->next)
+            if (child->type == XML_TEXT_NODE)
+              puts ((char *) child->content);
+        }
+
+      print_labels (node->children);
+    }
+}
+
+static void
+print_attributes (xmlNode * a_node)
+{
+  for (xmlNode *node = a_node; node; node = node->next)
+    {
+      if (node->type == XML_ELEMENT_NODE)
+        {
+          printf ("%s", node->name);
+          for (xmlAttr *attr = node->properties; attr; attr = attr->next)
+            {
+              printf (" %s", attr->name);
+              if (!strcmp ((char *) attr->name, "baseFormat"))
+                printf ("=%s", (char *) xmlGetProp (node, attr->name));
+            }
+          putchar ('\n');
+        }
+
+      print_attributes (node->children);
+    }
+}
+
+static void
+print_string(xmlChar *s)
 {
-  if (argc != 2)
+  for (char *p = (char *) s; *p; p++)
+    if (*p == '\n')
+      printf ("\\n");
+    else
+      putchar (*p);
+}
+
+static void
+print_cdata (xmlNode * a_node)
+{
+  for (xmlNode *node = a_node; node; node = node->next)
     {
-      fprintf (stderr, "usage: %s FILE.xml\n", argv[0]);
+      if (node->type == XML_CDATA_SECTION_NODE)
+        {
+          print_string (node->content);
+          putchar ('\n');
+        }
+
+      print_cdata (node->children);
+    }
+}
+
+static void
+print_attribute (xmlNode *node, const char *attr)
+{
+  for (; node; node = node->next)
+    {
+      const char *s = (char *) xmlGetProp (node, (xmlChar *) attr);
+      if (s)
+        printf ("%s %s=%s\n", node->name, attr, s);
+
+      print_attribute (node->children, attr);
+    }
+}
+
+static void
+print_xml (xmlDoc *doc, xmlNode *node)
+{
+  xmlBuffer *buf = xmlBufferCreate();
+  xmlNodeDump (buf, doc, node, 0, 0);
+  xmlBufferDump (stdout, buf);
+  xmlBufferFree (buf);
+  putchar ('\n');
+}
+
+static void
+print_element (xmlDoc *doc, xmlNode *node, const char *element)
+{
+  for (; node; node = node->next)
+    {
+      if (node->name && !strcmp(element, (char *) node->name))
+        print_xml (doc, node);
+
+      print_element (doc, node->children, element);
+    }
+}
+
+static void
+print_id (xmlDoc *doc, xmlNode *node, const char *id)
+{
+  for (; node; node = node->next)
+    {
+      if (node->type == XML_ELEMENT_NODE)
+        {
+          const char *node_id = (char *) xmlGetProp (node, (xmlChar *) "id");
+          if (node_id && !strcmp (node_id, id))
+            {
+              print_xml (doc, node);
+              break;
+            }
+        }
+
+      print_id (doc, node->children, id);
+    }
+}
+
+static __attribute__((unused)) xmlNode *
+find_node (xmlNode *node, const char *name)
+{
+  for (; node; node = node->next)
+    {
+      if (node->name && !strcmp ((char *) node->name, name))
+        return node;
+
+      xmlNode *ps = find_node (node->children, name);
+      if (ps)
+        return ps;
+    }
+  return NULL;
+}
+
+static void
+print_text (xmlNode *node)
+{
+  for (; node; node = node->next)
+    {
+      if (node->type == XML_ELEMENT_NODE)
+        {
+          printf ("%s", node->name);
+          for (xmlNode *child = node->children; child; child = child->next)
+            if (child->type == XML_TEXT_NODE)
+              {
+                putchar (' ');
+                print_string (child->content);
+              }
+          putchar ('\n');
+        }
+
+      print_text (node->children);
+    }
+}
+
+static void
+check_version (xmlNode *root, const char *version)
+{
+  const char *s = (char *) xmlGetProp (root, (xmlChar *) "version");
+  if (!s)
+    {
+      fprintf (stderr, "missing version\n");
       exit (1);
     }
+  else if (strcmp(version, s))
+    {
+      exit (0);
+    }
+}
+
+static void
+usage (void)
+{
+  fprintf (stderr, "usage: parse-xml FILE.xml containment|attributes\n");
+  exit (1);
+}
+
+int
+main (int argc, char **argv)
+{
+  if (argc < 3)
+    usage ();
 
   LIBXML_TEST_VERSION;
 
-  xmlDoc *doc = xmlReadFile(argv[1], NULL, 0);
+  xmlDoc *doc = xmlReadFile(argv[1], NULL, XML_PARSE_NOBLANKS);
   if (doc == NULL)
     {
       fprintf (stderr, "error: could not parse file %s\n", argv[1]);
@@ -39,7 +278,46 @@ main (int argc, char **argv)
     }
 
   xmlNode *root = xmlDocGetRootElement(doc);
-  print_containment(root);
+
+  for (int i = 2; i < argc; i++)
+    {
+      if (!strcmp(argv[i], "parents"))
+        print_parents (root);
+      else if (!strcmp(argv[i], "containment"))
+        print_containment (root);
+      else if (!strcmp(argv[i], "attributes"))
+        print_attributes (root);
+      else if (!strcmp(argv[i], "cdata"))
+        print_cdata (root);
+      else if (!strcmp(argv[i], "text"))
+        print_text (root);
+      else if (!strncmp(argv[i], "element:", 8))
+        print_element (doc, root, argv[i] + 8);
+      else if (!strncmp(argv[i], "attr:", 5))
+        print_attribute (root, argv[i] + 5);
+      else if (!strncmp(argv[i], "id:", 3))
+        print_id (doc, root, argv[i] + 3);
+      else if (!strncmp(argv[i], "root:", 5))
+        {
+          /* Limit content to descendants of the given node. */
+          root = find_node (root, argv[i] + 5);
+          if (!root)
+            return 0;
+          root->next = NULL;
+        }
+      else if (!strncmp(argv[i], "musthave:", 9))
+        {
+          if (!find_node (root, argv[i] + 9))
+            return 0;
+        }
+      else if (!strcmp(argv[i], "labels"))
+        print_labels (root);
+      else if (!strncmp(argv[i], "version=", 8))
+        check_version (root, argv[i] + 8);
+      else
+        usage ();
+    }
+
   xmlFreeDoc(doc);
   xmlCleanupParser();