start moving beyond PMModelItemInfo
[pspp] / parse-xml.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <libxml/parser.h>
4 #include <libxml/tree.h>
5
6 static void
7 print_parents(xmlNode *node)
8 {
9   for (; node; node = node->next)
10     {
11       if (node->type == XML_ELEMENT_NODE)
12         {
13           for (xmlNode *child = node->children; child; child = child->next)
14             {
15               if (child->type == XML_ELEMENT_NODE)
16                   printf ("%s %s\n", node->name, child->name);
17               else if (child->type == XML_TEXT_NODE)
18                 printf ("%s <text>\n", node->name);
19               else if (child->type == XML_CDATA_SECTION_NODE)
20                 printf ("%s <cdata>\n", node->name);
21               else if (child->type == XML_COMMENT_NODE)
22                 printf ("%s <comment>\n", node->name);
23               else
24                 printf ("%s <%d>\n", node->name, child->type);
25             }
26         }
27
28       print_parents (node->children);
29     }
30 }
31
32 static void
33 print_containment (xmlNode *node)
34 {
35   for (; node; node = node->next)
36     {
37       if (node->type == XML_ELEMENT_NODE)
38         {
39           const char *child_names[512];
40           int child_name_cnt[512];
41           int n_names = 0;
42           for (xmlNode *child = node->children; child; child = child->next)
43             {
44               const char *name;
45
46               if (child->type == XML_ELEMENT_NODE)
47                 name = (char *) child->name;
48               else if (child->type == XML_TEXT_NODE)
49                 name = "<text>";
50               else if (child->type == XML_CDATA_SECTION_NODE)
51                 name = "<cdata>";
52               else if (child->type == XML_COMMENT_NODE)
53                 {
54                   name = "<comment>";
55                   //printf ("comment %s\n", (char *) child->content);
56                   continue;
57                 }
58               else
59                 name = "<other>";
60
61               for (int i = 0; i < n_names; i++)
62                 if (!strcmp(name, child_names[i]))
63                   {
64                     child_name_cnt[i]++;
65                     goto next;
66                   }
67               child_names[n_names] = name;
68               child_name_cnt[n_names] = 1;
69               n_names++;
70
71             next:;
72             }
73
74           printf ("%s", node->name);
75           for (int i = 0; i < n_names; i++)
76             {
77               printf (" %s", child_names[i]);
78               if (child_name_cnt[i] > 1)
79                 printf ("+");
80             }
81           printf ("\n");
82         }
83
84       print_containment (node->children);
85     }
86 }
87
88 static void
89 print_labels (xmlNode *node)
90 {
91   for (; node; node = node->next)
92     {
93       if (node->type == XML_ELEMENT_NODE
94           && !strcmp((char *) node->name, "label")
95           && node->parent->type == XML_ELEMENT_NODE
96           && !strcmp((char *) node->parent->name, "container"))
97         {
98           for (xmlNode *child = node->children; child; child = child->next)
99             if (child->type == XML_TEXT_NODE)
100               puts ((char *) child->content);
101         }
102
103       print_labels (node->children);
104     }
105 }
106
107 static void
108 print_attributes (xmlNode * a_node)
109 {
110   for (xmlNode *node = a_node; node; node = node->next)
111     {
112       if (node->type == XML_ELEMENT_NODE)
113         {
114           printf ("%s", node->name);
115           for (xmlAttr *attr = node->properties; attr; attr = attr->next)
116             {
117               printf (" %s", attr->name);
118               if (!strcmp ((char *) attr->name, "baseFormat"))
119                 printf ("=%s", (char *) xmlGetProp (node, attr->name));
120             }
121           putchar ('\n');
122         }
123
124       print_attributes (node->children);
125     }
126 }
127
128 static void
129 print_string(xmlChar *s)
130 {
131   for (char *p = (char *) s; *p; p++)
132     if (*p == '\n')
133       printf ("\\n");
134     else
135       putchar (*p);
136 }
137
138 static void
139 print_cdata (xmlNode * a_node)
140 {
141   for (xmlNode *node = a_node; node; node = node->next)
142     {
143       if (node->type == XML_CDATA_SECTION_NODE)
144         {
145           print_string (node->content);
146           putchar ('\n');
147         }
148
149       print_cdata (node->children);
150     }
151 }
152
153 static void
154 print_attribute (xmlNode *node, const char *attr)
155 {
156   for (; node; node = node->next)
157     {
158       const char *s = (char *) xmlGetProp (node, (xmlChar *) attr);
159       if (s)
160         printf ("%s %s=%s\n", node->name, attr, s);
161
162       print_attribute (node->children, attr);
163     }
164 }
165
166 static void
167 print_xml (xmlDoc *doc, xmlNode *node)
168 {
169   xmlBuffer *buf = xmlBufferCreate();
170   xmlNodeDump (buf, doc, node, 0, 0);
171   xmlBufferDump (stdout, buf);
172   xmlBufferFree (buf);
173   putchar ('\n');
174 }
175
176 static void
177 print_element (xmlDoc *doc, xmlNode *node, const char *element)
178 {
179   for (; node; node = node->next)
180     {
181       if (node->name && !strcmp(element, (char *) node->name))
182         print_xml (doc, node);
183
184       print_element (doc, node->children, element);
185     }
186 }
187
188 static void
189 print_id (xmlDoc *doc, xmlNode *node, const char *id)
190 {
191   for (; node; node = node->next)
192     {
193       if (node->type == XML_ELEMENT_NODE)
194         {
195           const char *node_id = (char *) xmlGetProp (node, (xmlChar *) "id");
196           if (node_id && !strcmp (node_id, id))
197             {
198               print_xml (doc, node);
199               break;
200             }
201         }
202
203       print_id (doc, node->children, id);
204     }
205 }
206
207 static __attribute__((unused)) xmlNode *
208 find_node (xmlNode *node, const char *name)
209 {
210   for (; node; node = node->next)
211     {
212       if (node->name && !strcmp ((char *) node->name, name))
213         return node;
214
215       xmlNode *ps = find_node (node->children, name);
216       if (ps)
217         return ps;
218     }
219   return NULL;
220 }
221
222 static void
223 print_text (xmlNode *node)
224 {
225   for (; node; node = node->next)
226     {
227       if (node->type == XML_ELEMENT_NODE)
228         {
229           printf ("%s", node->name);
230           for (xmlNode *child = node->children; child; child = child->next)
231             if (child->type == XML_TEXT_NODE)
232               {
233                 putchar (' ');
234                 print_string (child->content);
235               }
236           putchar ('\n');
237         }
238
239       print_text (node->children);
240     }
241 }
242
243 static void
244 check_version (xmlNode *root, const char *version)
245 {
246   const char *s = (char *) xmlGetProp (root, (xmlChar *) "version");
247   if (!s)
248     {
249       fprintf (stderr, "missing version\n");
250       exit (1);
251     }
252   else if (strcmp(version, s))
253     {
254       exit (0);
255     }
256 }
257
258 static void
259 usage (void)
260 {
261   fprintf (stderr, "usage: parse-xml FILE.xml containment|attributes\n");
262   exit (1);
263 }
264
265 int
266 main (int argc, char **argv)
267 {
268   if (argc < 3)
269     usage ();
270
271   LIBXML_TEST_VERSION;
272
273   xmlDoc *doc = xmlReadFile(argv[1], NULL, XML_PARSE_NOBLANKS);
274   if (doc == NULL)
275     {
276       fprintf (stderr, "error: could not parse file %s\n", argv[1]);
277       exit (1);
278     }
279
280   xmlNode *root = xmlDocGetRootElement(doc);
281
282   for (int i = 2; i < argc; i++)
283     {
284       if (!strcmp(argv[i], "parents"))
285         print_parents (root);
286       else if (!strcmp(argv[i], "containment"))
287         print_containment (root);
288       else if (!strcmp(argv[i], "attributes"))
289         print_attributes (root);
290       else if (!strcmp(argv[i], "cdata"))
291         print_cdata (root);
292       else if (!strcmp(argv[i], "text"))
293         print_text (root);
294       else if (!strncmp(argv[i], "element:", 8))
295         print_element (doc, root, argv[i] + 8);
296       else if (!strncmp(argv[i], "attr:", 5))
297         print_attribute (root, argv[i] + 5);
298       else if (!strncmp(argv[i], "id:", 3))
299         print_id (doc, root, argv[i] + 3);
300       else if (!strncmp(argv[i], "root:", 5))
301         {
302           /* Limit content to descendants of the given node. */
303           root = find_node (root, argv[i] + 5);
304           if (!root)
305             return 0;
306           root->next = NULL;
307         }
308       else if (!strncmp(argv[i], "musthave:", 9))
309         {
310           if (!find_node (root, argv[i] + 9))
311             return 0;
312         }
313       else if (!strcmp(argv[i], "labels"))
314         print_labels (root);
315       else if (!strncmp(argv[i], "version=", 8))
316         check_version (root, argv[i] + 8);
317       else
318         usage ();
319     }
320
321   xmlFreeDoc(doc);
322   xmlCleanupParser();
323
324   return 0;
325 }