Annotation of XML/debugXML.c, revision 1.17
1.1 daniel 1: /*
2: * debugXML.c : This is a set of routines used for debugging the tree
3: * produced by the XML parser.
4: *
1.2 daniel 5: * See Copyright for the status of this software.
6: *
1.1 daniel 7: * Daniel Veillard <Daniel.Veillard@w3.org>
8: */
9:
1.11 daniel 10: #ifdef WIN32
11: #include "win32config.h"
12: #else
13: #include "config.h"
14: #endif
1.1 daniel 15: #include <stdio.h>
1.12 daniel 16: #ifdef HAVE_STDLIB_H
17: #include <stdlib.h>
18: #endif
1.14 daniel 19: #ifdef HAVE_STRING_H
20: #include <string.h>
21: #endif
1.12 daniel 22: #include "xmlmemory.h"
1.1 daniel 23: #include "tree.h"
24: #include "parser.h"
25: #include "debugXML.h"
1.12 daniel 26: #include "HTMLtree.h"
27: #include "HTMLparser.h"
1.1 daniel 28:
29: #define IS_BLANK(c) \
30: (((c) == '\n') || ((c) == '\r') || ((c) == '\t') || ((c) == ' '))
31:
1.6 daniel 32: void xmlDebugDumpString(FILE *output, const xmlChar *str) {
1.1 daniel 33: int i;
34: for (i = 0;i < 40;i++)
35: if (str[i] == 0) return;
36: else if (IS_BLANK(str[i])) fputc(' ', output);
37: else fputc(str[i], output);
38: fprintf(output, "...");
39: }
40:
41: void xmlDebugDumpNamespace(FILE *output, xmlNsPtr ns, int depth) {
42: int i;
43: char shift[100];
44:
45: for (i = 0;((i < depth) && (i < 25));i++)
46: shift[2 * i] = shift[2 * i + 1] = ' ';
47: shift[2 * i] = shift[2 * i + 1] = 0;
48:
49: fprintf(output, shift);
50: if (ns->type == XML_GLOBAL_NAMESPACE)
51: fprintf(output, "old ");
1.10 daniel 52: if (ns->prefix != NULL)
53: fprintf(output, "namespace %s href=", ns->prefix);
54: else
1.12 daniel 55: fprintf(output, "default namespace href=");
1.10 daniel 56:
1.1 daniel 57: xmlDebugDumpString(output, ns->href);
58: fprintf(output, "\n");
59: }
60:
61: void xmlDebugDumpNamespaceList(FILE *output, xmlNsPtr ns, int depth) {
62: while (ns != NULL) {
63: xmlDebugDumpNamespace(output, ns, depth);
64: ns = ns->next;
65: }
66: }
67:
68: void xmlDebugDumpEntity(FILE *output, xmlEntityPtr ent, int depth) {
69: int i;
70: char shift[100];
71:
72: for (i = 0;((i < depth) && (i < 25));i++)
73: shift[2 * i] = shift[2 * i + 1] = ' ';
74: shift[2 * i] = shift[2 * i + 1] = 0;
75:
76: fprintf(output, shift);
77: switch (ent->type) {
78: case XML_INTERNAL_GENERAL_ENTITY:
79: fprintf(output, "INTERNAL_GENERAL_ENTITY ");
80: break;
81: case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
82: fprintf(output, "EXTERNAL_GENERAL_PARSED_ENTITY ");
83: break;
84: case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
85: fprintf(output, "EXTERNAL_GENERAL_UNPARSED_ENTITY ");
86: break;
87: case XML_INTERNAL_PARAMETER_ENTITY:
88: fprintf(output, "INTERNAL_PARAMETER_ENTITY ");
89: break;
90: case XML_EXTERNAL_PARAMETER_ENTITY:
91: fprintf(output, "EXTERNAL_PARAMETER_ENTITY ");
92: break;
93: default:
94: fprintf(output, "ENTITY_%d ! ", ent->type);
95: }
96: fprintf(output, "%s\n", ent->name);
97: if (ent->ExternalID) {
98: fprintf(output, shift);
99: fprintf(output, "ExternalID=%s\n", ent->ExternalID);
100: }
101: if (ent->SystemID) {
102: fprintf(output, shift);
103: fprintf(output, "SystemID=%s\n", ent->SystemID);
104: }
105: if (ent->content) {
106: fprintf(output, shift);
107: fprintf(output, "content=");
108: xmlDebugDumpString(output, ent->content);
109: fprintf(output, "\n");
110: }
111: }
112:
113: void xmlDebugDumpAttr(FILE *output, xmlAttrPtr attr, int depth) {
114: int i;
115: char shift[100];
116:
117: for (i = 0;((i < depth) && (i < 25));i++)
118: shift[2 * i] = shift[2 * i + 1] = ' ';
119: shift[2 * i] = shift[2 * i + 1] = 0;
120:
121: fprintf(output, shift);
122: fprintf(output, "ATTRIBUTE %s\n", attr->name);
1.16 daniel 123: if (attr->children != NULL)
124: xmlDebugDumpNodeList(output, attr->children, depth + 1);
1.1 daniel 125: }
126:
127: void xmlDebugDumpAttrList(FILE *output, xmlAttrPtr attr, int depth) {
128: while (attr != NULL) {
129: xmlDebugDumpAttr(output, attr, depth);
130: attr = attr->next;
131: }
132: }
133:
1.3 daniel 134: void xmlDebugDumpOneNode(FILE *output, xmlNodePtr node, int depth) {
1.1 daniel 135: int i;
136: char shift[100];
137:
138: for (i = 0;((i < depth) && (i < 25));i++)
139: shift[2 * i] = shift[2 * i + 1] = ' ';
140: shift[2 * i] = shift[2 * i + 1] = 0;
141:
142: fprintf(output, shift);
143: switch (node->type) {
144: case XML_ELEMENT_NODE:
145: fprintf(output, "ELEMENT ");
146: if (node->ns != NULL)
147: fprintf(output, "%s:%s\n", node->ns->prefix, node->name);
148: else
149: fprintf(output, "%s\n", node->name);
150: break;
151: case XML_ATTRIBUTE_NODE:
152: fprintf(output, "Error, ATTRIBUTE found here\n");
153: break;
154: case XML_TEXT_NODE:
155: fprintf(output, "TEXT\n");
156: break;
157: case XML_CDATA_SECTION_NODE:
158: fprintf(output, "CDATA_SECTION\n");
159: break;
160: case XML_ENTITY_REF_NODE:
1.15 daniel 161: fprintf(output, "ENTITY_REF(%s)\n", node->name);
1.1 daniel 162: break;
163: case XML_ENTITY_NODE:
164: fprintf(output, "ENTITY\n");
165: break;
166: case XML_PI_NODE:
1.4 daniel 167: fprintf(output, "PI %s\n", node->name);
1.1 daniel 168: break;
169: case XML_COMMENT_NODE:
170: fprintf(output, "COMMENT\n");
171: break;
172: case XML_DOCUMENT_NODE:
1.7 daniel 173: case XML_HTML_DOCUMENT_NODE:
1.1 daniel 174: fprintf(output, "Error, DOCUMENT found here\n");
175: break;
176: case XML_DOCUMENT_TYPE_NODE:
177: fprintf(output, "DOCUMENT_TYPE\n");
178: break;
179: case XML_DOCUMENT_FRAG_NODE:
180: fprintf(output, "DOCUMENT_FRAG\n");
181: break;
182: case XML_NOTATION_NODE:
183: fprintf(output, "NOTATION\n");
184: break;
185: default:
186: fprintf(output, "NODE_%d\n", node->type);
187: }
188: if (node->doc == NULL) {
189: fprintf(output, shift);
190: fprintf(output, "doc == NULL !!!\n");
191: }
192: if (node->nsDef != NULL)
193: xmlDebugDumpNamespaceList(output, node->nsDef, depth + 1);
194: if (node->properties != NULL)
195: xmlDebugDumpAttrList(output, node->properties, depth + 1);
196: if (node->type != XML_ENTITY_REF_NODE) {
197: if (node->content != NULL) {
198: fprintf(output, shift);
199: fprintf(output, "content=");
1.8 daniel 200: #ifndef XML_USE_BUFFER_CONTENT
1.1 daniel 201: xmlDebugDumpString(output, node->content);
1.8 daniel 202: #else
203: xmlDebugDumpString(output, xmlBufferContent(node->content));
204: #endif
1.1 daniel 205: fprintf(output, "\n");
206: }
207: } else {
208: xmlEntityPtr ent;
209: ent = xmlGetDocEntity(node->doc, node->name);
210: if (ent != NULL)
211: xmlDebugDumpEntity(output, ent, depth + 1);
212: }
1.3 daniel 213: }
214:
215: void xmlDebugDumpNode(FILE *output, xmlNodePtr node, int depth) {
216: xmlDebugDumpOneNode(output, node, depth);
1.16 daniel 217: if (node->children != NULL)
218: xmlDebugDumpNodeList(output, node->children, depth + 1);
1.1 daniel 219: }
220:
221: void xmlDebugDumpNodeList(FILE *output, xmlNodePtr node, int depth) {
222: while (node != NULL) {
223: xmlDebugDumpNode(output, node, depth);
224: node = node->next;
225: }
226: }
227:
228:
1.12 daniel 229: void xmlDebugDumpDocumentHead(FILE *output, xmlDocPtr doc) {
1.1 daniel 230: if (output == NULL) output = stdout;
231: if (doc == NULL) {
232: fprintf(output, "DOCUMENT == NULL !\n");
233: return;
234: }
235:
236: switch (doc->type) {
237: case XML_ELEMENT_NODE:
238: fprintf(output, "Error, ELEMENT found here ");
239: break;
240: case XML_ATTRIBUTE_NODE:
241: fprintf(output, "Error, ATTRIBUTE found here\n");
242: break;
243: case XML_TEXT_NODE:
244: fprintf(output, "Error, TEXT\n");
245: break;
246: case XML_CDATA_SECTION_NODE:
247: fprintf(output, "Error, CDATA_SECTION\n");
248: break;
249: case XML_ENTITY_REF_NODE:
250: fprintf(output, "Error, ENTITY_REF\n");
251: break;
252: case XML_ENTITY_NODE:
253: fprintf(output, "Error, ENTITY\n");
254: break;
255: case XML_PI_NODE:
256: fprintf(output, "Error, PI\n");
257: break;
258: case XML_COMMENT_NODE:
259: fprintf(output, "Error, COMMENT\n");
260: break;
261: case XML_DOCUMENT_NODE:
262: fprintf(output, "DOCUMENT\n");
1.7 daniel 263: break;
264: case XML_HTML_DOCUMENT_NODE:
265: fprintf(output, "HTML DOCUMENT\n");
1.1 daniel 266: break;
267: case XML_DOCUMENT_TYPE_NODE:
268: fprintf(output, "Error, DOCUMENT_TYPE\n");
269: break;
270: case XML_DOCUMENT_FRAG_NODE:
271: fprintf(output, "Error, DOCUMENT_FRAG\n");
272: break;
273: case XML_NOTATION_NODE:
274: fprintf(output, "Error, NOTATION\n");
275: break;
276: default:
277: fprintf(output, "NODE_%d\n", doc->type);
278: }
279: if (doc->name != NULL) {
280: fprintf(output, "name=");
1.5 daniel 281: xmlDebugDumpString(output, BAD_CAST doc->name);
1.1 daniel 282: fprintf(output, "\n");
283: }
284: if (doc->version != NULL) {
285: fprintf(output, "version=");
286: xmlDebugDumpString(output, doc->version);
287: fprintf(output, "\n");
288: }
289: if (doc->encoding != NULL) {
290: fprintf(output, "encoding=");
291: xmlDebugDumpString(output, doc->encoding);
292: fprintf(output, "\n");
293: }
294: if (doc->standalone)
295: fprintf(output, "standalone=true\n");
296: if (doc->oldNs != NULL)
297: xmlDebugDumpNamespaceList(output, doc->oldNs, 0);
1.12 daniel 298: }
299:
300: void xmlDebugDumpDocument(FILE *output, xmlDocPtr doc) {
301: if (output == NULL) output = stdout;
302: if (doc == NULL) {
303: fprintf(output, "DOCUMENT == NULL !\n");
304: return;
305: }
306: xmlDebugDumpDocumentHead(output, doc);
307: if (((doc->type == XML_DOCUMENT_NODE) ||
308: (doc->type == XML_HTML_DOCUMENT_NODE)) &&
1.16 daniel 309: (doc->children != NULL))
310: xmlDebugDumpNodeList(output, doc->children, 1);
1.12 daniel 311: }
1.9 daniel 312:
313: void xmlDebugDumpEntities(FILE *output, xmlDocPtr doc) {
314: int i;
315: xmlEntityPtr cur;
316:
317: if (output == NULL) output = stdout;
318: if (doc == NULL) {
319: fprintf(output, "DOCUMENT == NULL !\n");
320: return;
321: }
322:
323: switch (doc->type) {
324: case XML_ELEMENT_NODE:
325: fprintf(output, "Error, ELEMENT found here ");
326: break;
327: case XML_ATTRIBUTE_NODE:
328: fprintf(output, "Error, ATTRIBUTE found here\n");
329: break;
330: case XML_TEXT_NODE:
331: fprintf(output, "Error, TEXT\n");
332: break;
333: case XML_CDATA_SECTION_NODE:
334: fprintf(output, "Error, CDATA_SECTION\n");
335: break;
336: case XML_ENTITY_REF_NODE:
337: fprintf(output, "Error, ENTITY_REF\n");
338: break;
339: case XML_ENTITY_NODE:
340: fprintf(output, "Error, ENTITY\n");
341: break;
342: case XML_PI_NODE:
343: fprintf(output, "Error, PI\n");
344: break;
345: case XML_COMMENT_NODE:
346: fprintf(output, "Error, COMMENT\n");
347: break;
348: case XML_DOCUMENT_NODE:
349: fprintf(output, "DOCUMENT\n");
350: break;
351: case XML_HTML_DOCUMENT_NODE:
352: fprintf(output, "HTML DOCUMENT\n");
353: break;
354: case XML_DOCUMENT_TYPE_NODE:
355: fprintf(output, "Error, DOCUMENT_TYPE\n");
356: break;
357: case XML_DOCUMENT_FRAG_NODE:
358: fprintf(output, "Error, DOCUMENT_FRAG\n");
359: break;
360: case XML_NOTATION_NODE:
361: fprintf(output, "Error, NOTATION\n");
362: break;
363: default:
364: fprintf(output, "NODE_%d\n", doc->type);
365: }
366: if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
367: xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
368: doc->intSubset->entities;
369: fprintf(output, "Entities in internal subset\n");
370: for (i = 0;i < table->nb_entities;i++) {
371: cur = &table->table[i];
372: fprintf(output, "%d : %s : ", i, cur->name);
373: switch (cur->type) {
374: case XML_INTERNAL_GENERAL_ENTITY:
375: fprintf(output, "INTERNAL GENERAL");
376: break;
377: case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
378: fprintf(output, "EXTERNAL PARSED");
379: break;
380: case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
381: fprintf(output, "EXTERNAL UNPARSED");
382: break;
383: case XML_INTERNAL_PARAMETER_ENTITY:
384: fprintf(output, "INTERNAL PARAMETER");
385: break;
386: case XML_EXTERNAL_PARAMETER_ENTITY:
387: fprintf(output, "EXTERNAL PARAMETER");
388: break;
389: default:
390: fprintf(output, "UNKNOWN TYPE %d",
391: cur->type);
392: }
393: if (cur->ExternalID != NULL)
394: fprintf(output, "ID \"%s\"", cur->ExternalID);
395: if (cur->SystemID != NULL)
396: fprintf(output, "SYSTEM \"%s\"", cur->SystemID);
397: if (cur->orig != NULL)
398: fprintf(output, "\n orig \"%s\"", cur->orig);
399: if (cur->content != NULL)
400: fprintf(output, "\n content \"%s\"", cur->content);
401: fprintf(output, "\n");
402: }
403: } else
404: fprintf(output, "No entities in internal subset\n");
405: if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
406: xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
407: doc->extSubset->entities;
408: fprintf(output, "Entities in external subset\n");
409: for (i = 0;i < table->nb_entities;i++) {
410: cur = &table->table[i];
411: fprintf(output, "%d : %s : ", i, cur->name);
412: switch (cur->type) {
413: case XML_INTERNAL_GENERAL_ENTITY:
414: fprintf(output, "INTERNAL GENERAL");
415: break;
416: case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
417: fprintf(output, "EXTERNAL PARSED");
418: break;
419: case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
420: fprintf(output, "EXTERNAL UNPARSED");
421: break;
422: case XML_INTERNAL_PARAMETER_ENTITY:
423: fprintf(output, "INTERNAL PARAMETER");
424: break;
425: case XML_EXTERNAL_PARAMETER_ENTITY:
426: fprintf(output, "EXTERNAL PARAMETER");
427: break;
428: default:
429: fprintf(output, "UNKNOWN TYPE %d",
430: cur->type);
431: }
432: if (cur->ExternalID != NULL)
433: fprintf(output, "ID \"%s\"", cur->ExternalID);
434: if (cur->SystemID != NULL)
435: fprintf(output, "SYSTEM \"%s\"", cur->SystemID);
436: if (cur->orig != NULL)
437: fprintf(output, "\n orig \"%s\"", cur->orig);
438: if (cur->content != NULL)
439: fprintf(output, "\n content \"%s\"", cur->content);
440: fprintf(output, "\n");
441: }
442: } else
443: fprintf(output, "No entities in external subset\n");
444: }
1.12 daniel 445:
446: static int xmlLsCountNode(xmlNodePtr node) {
447: int ret = 0;
448: xmlNodePtr list = NULL;
449:
450: switch (node->type) {
451: case XML_ELEMENT_NODE:
1.16 daniel 452: list = node->children;
1.12 daniel 453: break;
454: case XML_DOCUMENT_NODE:
455: case XML_HTML_DOCUMENT_NODE:
1.16 daniel 456: list = ((xmlDocPtr) node)->children;
1.12 daniel 457: break;
458: case XML_ATTRIBUTE_NODE:
1.16 daniel 459: list = ((xmlAttrPtr) node)->children;
1.12 daniel 460: break;
461: case XML_TEXT_NODE:
462: case XML_CDATA_SECTION_NODE:
463: case XML_PI_NODE:
464: case XML_COMMENT_NODE:
465: if (node->content != NULL) {
466: #ifndef XML_USE_BUFFER_CONTENT
467: ret = xmlStrlen(node->content);
468: #else
469: ret = xmlBufferLength(node->content);
470: #endif
471: }
472: break;
473: case XML_ENTITY_REF_NODE:
474: case XML_DOCUMENT_TYPE_NODE:
475: case XML_ENTITY_NODE:
476: case XML_DOCUMENT_FRAG_NODE:
477: case XML_NOTATION_NODE:
1.16 daniel 478: case XML_DTD_NODE:
1.17 ! daniel 479: case XML_ELEMENT_DECL:
! 480: case XML_ATTRIBUTE_DECL:
1.12 daniel 481: ret = 1;
482: break;
483: }
484: for (;list != NULL;ret++)
485: list = list->next;
486: return(ret);
487: }
488:
489: void xmlLsOneNode(FILE *output, xmlNodePtr node) {
490: switch (node->type) {
491: case XML_ELEMENT_NODE:
492: fprintf(output, "-");
493: break;
494: case XML_ATTRIBUTE_NODE:
495: fprintf(output, "a");
496: break;
497: case XML_TEXT_NODE:
498: fprintf(output, "t");
499: break;
500: case XML_CDATA_SECTION_NODE:
501: fprintf(output, "c");
502: break;
503: case XML_ENTITY_REF_NODE:
504: fprintf(output, "e");
505: break;
506: case XML_ENTITY_NODE:
507: fprintf(output, "E");
508: break;
509: case XML_PI_NODE:
510: fprintf(output, "p");
511: break;
512: case XML_COMMENT_NODE:
513: fprintf(output, "c");
514: break;
515: case XML_DOCUMENT_NODE:
516: fprintf(output, "d");
517: break;
518: case XML_HTML_DOCUMENT_NODE:
519: fprintf(output, "h");
520: break;
521: case XML_DOCUMENT_TYPE_NODE:
522: fprintf(output, "T");
523: break;
524: case XML_DOCUMENT_FRAG_NODE:
525: fprintf(output, "F");
526: break;
527: case XML_NOTATION_NODE:
528: fprintf(output, "N");
529: break;
530: default:
531: fprintf(output, "?");
532: }
533: if (node->properties != NULL)
534: fprintf(output, "a");
535: else
536: fprintf(output, "-");
537: if (node->nsDef != NULL)
538: fprintf(output, "n");
539: else
540: fprintf(output, "-");
541:
542: fprintf(output, " %8d ", xmlLsCountNode(node));
543:
544: switch (node->type) {
545: case XML_ELEMENT_NODE:
546: if (node->name != NULL)
547: fprintf(output, "%s", node->name);
548: break;
549: case XML_ATTRIBUTE_NODE:
550: if (node->name != NULL)
551: fprintf(output, "%s", node->name);
552: break;
553: case XML_TEXT_NODE:
554: if (node->content != NULL) {
555: #ifndef XML_USE_BUFFER_CONTENT
556: xmlDebugDumpString(output, node->content);
557: #else
558: xmlDebugDumpString(output, xmlBufferContent(node->content));
559: #endif
560: }
561: break;
562: case XML_CDATA_SECTION_NODE:
563: break;
564: case XML_ENTITY_REF_NODE:
565: if (node->name != NULL)
566: fprintf(output, "%s", node->name);
567: break;
568: case XML_ENTITY_NODE:
569: if (node->name != NULL)
570: fprintf(output, "%s", node->name);
571: break;
572: case XML_PI_NODE:
573: if (node->name != NULL)
574: fprintf(output, "%s", node->name);
575: break;
576: case XML_COMMENT_NODE:
577: break;
578: case XML_DOCUMENT_NODE:
579: break;
580: case XML_HTML_DOCUMENT_NODE:
581: break;
582: case XML_DOCUMENT_TYPE_NODE:
583: break;
584: case XML_DOCUMENT_FRAG_NODE:
585: break;
586: case XML_NOTATION_NODE:
587: break;
588: default:
589: if (node->name != NULL)
590: fprintf(output, "%s", node->name);
591: }
592: fprintf(output, "\n");
593: }
594:
595: /****************************************************************
596: * *
597: * The XML shell related functions *
598: * *
599: ****************************************************************/
600:
601: /*
602: * TODO: Improvement/cleanups for the XML shell
603: * - allow to shell out an editor on a subpart
604: * - cleanup function registrations (with help) and calling
605: * - provide registration routines
606: */
607:
608: /**
609: * xmlShellList:
610: * @ctxt: the shell context
611: * @arg: unused
612: * @node: a node
613: * @node2: unused
614: *
615: * Implements the XML shell function "ls"
616: * Does an Unix like listing of the given node (like a directory)
617: *
618: * Returns 0
619: */
620: int
621: xmlShellList(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node,
622: xmlNodePtr node2) {
623: xmlNodePtr cur;
624:
625: if ((node->type == XML_DOCUMENT_NODE) ||
626: (node->type == XML_HTML_DOCUMENT_NODE)) {
1.16 daniel 627: cur = ((xmlDocPtr) node)->children;
628: } else if (node->children != NULL) {
629: cur = node->children;
1.12 daniel 630: } else {
631: xmlLsOneNode(stdout, node);
632: return(0);
633: }
634: while (cur != NULL) {
635: xmlLsOneNode(stdout, cur);
636: cur = cur->next;
637: }
638: return(0);
639: }
640:
641: /**
642: * xmlShellDir:
643: * @ctxt: the shell context
644: * @arg: unused
645: * @node: a node
646: * @node2: unused
647: *
648: * Implements the XML shell function "dir"
649: * dumps informations about the node (namespace, attributes, content).
650: *
651: * Returns 0
652: */
653: int
654: xmlShellDir(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node,
655: xmlNodePtr node2) {
656: if ((node->type == XML_DOCUMENT_NODE) ||
657: (node->type == XML_HTML_DOCUMENT_NODE)) {
658: xmlDebugDumpDocumentHead(stdout, (xmlDocPtr) node);
659: } else if (node->type == XML_ATTRIBUTE_NODE) {
660: xmlDebugDumpAttr(stdout, (xmlAttrPtr) node, 0);
661: } else {
662: xmlDebugDumpOneNode(stdout, node, 0);
663: }
664: return(0);
665: }
666:
667: /**
668: * xmlShellCat:
669: * @ctxt: the shell context
670: * @arg: unused
671: * @node: a node
672: * @node2: unused
673: *
674: * Implements the XML shell function "cat"
675: * dumps the serialization node content (XML or HTML).
676: *
677: * Returns 0
678: */
679: int
680: xmlShellCat(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node,
681: xmlNodePtr node2) {
1.13 daniel 682: if (ctxt->doc->type == XML_HTML_DOCUMENT_NODE) {
683: if (node->type == XML_HTML_DOCUMENT_NODE)
684: htmlDocDump(stdout, (htmlDocPtr) node);
685: else
1.14 daniel 686: htmlNodeDumpFile(stdout, ctxt->doc, node);
1.13 daniel 687: } else {
688: if (node->type == XML_DOCUMENT_NODE)
689: xmlDocDump(stdout, (xmlDocPtr) node);
690: else
691: xmlElemDump(stdout, ctxt->doc, node);
692: }
1.12 daniel 693: printf("\n");
694: return(0);
695: }
696:
697: /**
698: * xmlShellLoad:
699: * @ctxt: the shell context
700: * @filename: the file name
701: * @node: unused
702: * @node2: unused
703: *
704: * Implements the XML shell function "load"
705: * loads a new document specified by the filename
706: *
707: * Returns 0 or -1 if loading failed
708: */
709: int
710: xmlShellLoad(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
711: xmlNodePtr node2) {
712: xmlDocPtr doc;
713: int html = 0;
714:
715: if (ctxt->doc != NULL)
716: html = (ctxt->doc->type == XML_HTML_DOCUMENT_NODE);
717:
718: if (html) {
719: doc = htmlParseFile(filename, NULL);
720: } else {
721: doc = xmlParseFile(filename);
722: }
723: if (doc != NULL) {
724: if (ctxt->loaded == 1) {
725: xmlFreeDoc(ctxt->doc);
726: }
727: ctxt->loaded = 1;
728: xmlXPathFreeContext(ctxt->pctxt);
729: xmlFree(ctxt->filename);
730: ctxt->doc = doc;
731: ctxt->node = (xmlNodePtr) doc;
732: ctxt->pctxt = xmlXPathNewContext(doc);
733: ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
734: } else
735: return(-1);
736: return(0);
737: }
738:
739: /**
740: * xmlShellWrite:
741: * @ctxt: the shell context
742: * @filename: the file name
743: * @node: a node in the tree
744: * @node2: unused
745: *
746: * Implements the XML shell function "write"
747: * Write the current node to the filename, it saves the serailization
748: * of the subtree under the @node specified
749: *
750: * Returns 0 or -1 in case of error
751: */
752: int
753: xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
754: xmlNodePtr node2) {
755: if (node == NULL)
756: return(-1);
757: if ((filename == NULL) || (filename[0] == 0)) {
758: fprintf(stderr, "Write command requires a filename argument\n");
759: return(-1);
760: }
761: #ifdef W_OK
762: if (access((char *) filename, W_OK)) {
763: fprintf(stderr, "Cannot write to %s\n", filename);
764: return(-1);
765: }
766: #endif
767: switch(node->type) {
768: case XML_DOCUMENT_NODE:
769: if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
770: fprintf(stderr, "Failed to write to %s\n", filename);
771: return(-1);
772: }
773: break;
774: case XML_HTML_DOCUMENT_NODE:
775: if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
776: fprintf(stderr, "Failed to write to %s\n", filename);
777: return(-1);
778: }
779: break;
780: default: {
781: FILE *f;
782:
783: f = fopen((char *) filename, "w");
784: if (f == NULL) {
785: fprintf(stderr, "Failed to write to %s\n", filename);
786: return(-1);
787: }
788: xmlElemDump(f, ctxt->doc, node);
789: fclose(f);
790: }
791: }
792: return(0);
793: }
794:
795: /**
796: * xmlShellSave:
797: * @ctxt: the shell context
798: * @filename: the file name (optionnal)
799: * @node: unused
800: * @node2: unused
801: *
802: * Implements the XML shell function "save"
803: * Write the current document to the filename, or it's original name
804: *
805: * Returns 0 or -1 in case of error
806: */
807: int
808: xmlShellSave(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
809: xmlNodePtr node2) {
810: if (ctxt->doc == NULL)
811: return(-1);
812: if ((filename == NULL) || (filename[0] == 0))
813: filename = ctxt->filename;
814: #ifdef W_OK
815: if (access((char *) filename, W_OK)) {
816: fprintf(stderr, "Cannot save to %s\n", filename);
817: return(-1);
818: }
819: #endif
820: switch(ctxt->doc->type) {
821: case XML_DOCUMENT_NODE:
822: if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
823: fprintf(stderr, "Failed to save to %s\n", filename);
824: }
825: break;
826: case XML_HTML_DOCUMENT_NODE:
827: if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
828: fprintf(stderr, "Failed to save to %s\n", filename);
829: }
830: break;
831: default:
832: fprintf(stderr,
833: "To save to subparts of a document use the 'write' command\n");
834: return(-1);
835:
836: }
837: return(0);
838: }
839:
840: /**
841: * xmlShellValidate:
842: * @ctxt: the shell context
843: * @dtd: the DTD URI (optionnal)
844: * @node: unused
845: * @node2: unused
846: *
847: * Implements the XML shell function "validate"
848: * Validate the document, if a DTD path is provided, then the validation
849: * is done against the given DTD.
850: *
851: * Returns 0 or -1 in case of error
852: */
853: int
854: xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd, xmlNodePtr node,
855: xmlNodePtr node2) {
856: xmlValidCtxt vctxt;
857: int res = -1;
858:
859: vctxt.userData = stderr;
860: vctxt.error = (xmlValidityErrorFunc) fprintf;
861: vctxt.warning = (xmlValidityWarningFunc) fprintf;
862:
863: if ((dtd == NULL) || (dtd[0] == 0)) {
864: res = xmlValidateDocument(&vctxt, ctxt->doc);
865: } else {
866: xmlDtdPtr subset;
867:
868: subset = xmlParseDTD(NULL, (xmlChar *) dtd);
869: if (subset != NULL) {
870: res = xmlValidateDtd(&vctxt, ctxt->doc, subset);
871:
872: xmlFreeDtd(subset);
873: }
874: }
875: return(res);
876: }
877:
878: /**
879: * xmlShellDu:
880: * @ctxt: the shell context
881: * @arg: unused
882: * @tree: a node defining a subtree
883: * @node2: unused
884: *
885: * Implements the XML shell function "du"
886: * show the structure of the subtree under node @tree
887: * If @tree is null, the command works on the current node.
888: *
889: * Returns 0 or -1 in case of error
890: */
891: int
892: xmlShellDu(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr tree,
893: xmlNodePtr node2) {
894: xmlNodePtr node;
895: int indent = 0,i;
896:
897: if (tree == NULL) return(-1);
898: node = tree;
899: while (node != NULL) {
900: if ((node->type == XML_DOCUMENT_NODE) ||
901: (node->type == XML_HTML_DOCUMENT_NODE)) {
902: printf("/\n");
903: } else if (node->type == XML_ELEMENT_NODE) {
904: for (i = 0;i < indent;i++)
905: printf(" ");
906: printf("%s\n", node->name);
907: } else {
908: }
909:
910: /*
911: * Browse the full subtree, deep first
912: */
913:
914: if ((node->type == XML_DOCUMENT_NODE) ||
915: (node->type == XML_HTML_DOCUMENT_NODE)) {
1.16 daniel 916: node = ((xmlDocPtr) node)->children;
917: } else if (node->children != NULL) {
1.12 daniel 918: /* deep first */
1.16 daniel 919: node = node->children;
1.12 daniel 920: indent++;
921: } else if ((node != tree) && (node->next != NULL)) {
922: /* then siblings */
923: node = node->next;
924: } else if (node != tree) {
925: /* go up to parents->next if needed */
926: while (node != tree) {
927: if (node->parent != NULL) {
928: node = node->parent;
929: indent--;
930: }
931: if ((node != tree) && (node->next != NULL)) {
932: node = node->next;
933: break;
934: }
935: if (node->parent == NULL) {
936: node = NULL;
937: break;
938: }
939: if (node == tree) {
940: node = NULL;
941: break;
942: }
943: }
944: /* exit condition */
945: if (node == tree)
946: node = NULL;
947: } else
948: node = NULL;
949: }
950: return(0);
951: }
952:
953: /**
954: * xmlShellPwd:
955: * @ctxt: the shell context
956: * @buffer: the output buffer
957: * @tree: a node
958: * @node2: unused
959: *
960: * Implements the XML shell function "pwd"
961: * Show the full path from the root to the node, if needed building
962: * thumblers when similar elements exists at a given ancestor level.
963: * The output is compatible with XPath commands.
964: *
965: * Returns 0 or -1 in case of error
966: */
967: int
968: xmlShellPwd(xmlShellCtxtPtr ctxt, char *buffer, xmlNodePtr node,
969: xmlNodePtr node2) {
970: xmlNodePtr cur, tmp, next;
971: char buf[500];
972: char sep;
973: const char *name;
974: int occur = 0;
975:
976: buffer[0] = 0;
977: if (node == NULL) return(-1);
978: cur = node;
979: do {
980: name = "";
981: sep= '?';
982: occur = 0;
983: if ((cur->type == XML_DOCUMENT_NODE) ||
984: (cur->type == XML_HTML_DOCUMENT_NODE)) {
985: sep = '/';
986: next = NULL;
987: } else if (cur->type == XML_ELEMENT_NODE) {
988: sep = '/';
989: name = (const char *)cur->name;
990: next = cur->parent;
991:
992: /*
993: * Thumbler index computation
994: */
995: tmp = cur->prev;
996: while (tmp != NULL) {
997: if (!xmlStrcmp(cur->name, tmp->name))
998: occur++;
999: tmp = tmp->prev;
1000: }
1001: if (occur == 0) {
1002: tmp = cur->next;
1003: while (tmp != NULL) {
1004: if (!xmlStrcmp(cur->name, tmp->name))
1005: occur++;
1006: tmp = tmp->next;
1007: }
1008: if (occur != 0) occur = 1;
1009: } else
1010: occur++;
1011: } else if (cur->type == XML_ATTRIBUTE_NODE) {
1012: sep = '@';
1013: name = (const char *) (((xmlAttrPtr) cur)->name);
1.16 daniel 1014: next = ((xmlAttrPtr) cur)->parent;
1.12 daniel 1015: } else {
1016: next = cur->parent;
1017: }
1018: if (occur == 0)
1019: sprintf(buf, "%c%s%s", sep, name, buffer);
1020: else
1021: sprintf(buf, "%c%s[%d]%s", sep, name, occur, buffer);
1022: strcpy(buffer, buf);
1023: cur = next;
1024: } while (cur != NULL);
1025: return(0);
1026: }
1027:
1028: /**
1029: * xmlShell
1030: * @doc: the initial document
1031: * @filename: the output buffer
1032: * @input: the line reading function
1033: * @output: the output FILE*
1034: *
1035: * Implements the XML shell
1036: * This allow to load, validate, view, modify and save a document
1037: * using a environment similar to a UNIX commandline.
1038: */
1039: void
1040: xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input,
1041: FILE *output) {
1042: char prompt[500] = "/ > ";
1043: char *cmdline = NULL;
1044: int nbargs;
1045: char command[100];
1046: char arg[400];
1047: xmlShellCtxtPtr ctxt;
1048: xmlXPathObjectPtr list;
1049:
1050: if (doc == NULL)
1051: return;
1052: if (filename == NULL)
1053: return;
1054: if (input == NULL)
1055: return;
1056: if (output == NULL)
1057: return;
1058: ctxt = (xmlShellCtxtPtr) xmlMalloc(sizeof(xmlShellCtxt));
1059: if (ctxt == NULL)
1060: return;
1061: ctxt->loaded = 0;
1062: ctxt->doc = doc;
1063: ctxt->input = input;
1064: ctxt->output = output;
1065: ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
1066: ctxt->node = (xmlNodePtr) ctxt->doc;
1067:
1068: ctxt->pctxt = xmlXPathNewContext(ctxt->doc);
1069: if (ctxt->pctxt == NULL) {
1070: xmlFree(ctxt);
1071: return;
1072: }
1073: while (1) {
1074: if (ctxt->node == (xmlNodePtr) ctxt->doc)
1075: sprintf(prompt, "%s > ", "/");
1076: else if (ctxt->node->name)
1077: sprintf(prompt, "%s > ", ctxt->node->name);
1078: else
1079: sprintf(prompt, "? > ");
1080:
1081: cmdline = ctxt->input(prompt);
1082: if (cmdline == NULL) break;
1083:
1084: command[0] = 0;
1085: arg[0] = 0;
1086: nbargs = sscanf(cmdline, "%s %s", command, arg);
1087:
1088: if (command[0] == 0) continue;
1089: if (!strcmp(command, "exit"))
1090: break;
1091: if (!strcmp(command, "quit"))
1092: break;
1093: if (!strcmp(command, "bye"))
1094: break;
1095: if (!strcmp(command, "validate")) {
1096: xmlShellValidate(ctxt, arg, NULL, NULL);
1097: } else if (!strcmp(command, "load")) {
1098: xmlShellLoad(ctxt, arg, NULL, NULL);
1099: } else if (!strcmp(command, "save")) {
1100: xmlShellSave(ctxt, arg, NULL, NULL);
1101: } else if (!strcmp(command, "write")) {
1102: xmlShellWrite(ctxt, arg, NULL, NULL);
1103: } else if (!strcmp(command, "free")) {
1104: if (arg[0] == 0) {
1105: xmlMemShow(stdout, 0);
1106: } else {
1107: int len = 0;
1108: sscanf(arg, "%d", &len);
1109: xmlMemShow(stdout, len);
1110: }
1111: } else if (!strcmp(command, "pwd")) {
1112: char dir[500];
1113: if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL))
1114: printf("%s\n", dir);
1115: } else if (!strcmp(command, "du")) {
1116: xmlShellDu(ctxt, NULL, ctxt->node, NULL);
1117: } else if ((!strcmp(command, "ls")) ||
1118: (!strcmp(command, "dir"))) {
1119: int dir = (!strcmp(command, "dir"));
1120: if (arg[0] == 0) {
1121: if (dir)
1122: xmlShellDir(ctxt, NULL, ctxt->node, NULL);
1123: else
1124: xmlShellList(ctxt, NULL, ctxt->node, NULL);
1125: } else {
1126: ctxt->pctxt->node = ctxt->node;
1127: if (ctxt->pctxt->nodelist != NULL)
1128: xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
1129: ctxt->pctxt->nodelist = xmlXPathNodeSetCreate(ctxt->node);
1130: list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
1131: if (list != NULL) {
1132: switch (list->type) {
1133: case XPATH_UNDEFINED:
1134: fprintf(stderr, "%s: no such node\n", arg);
1135: break;
1136: case XPATH_NODESET: {
1137: int i;
1138:
1139: for (i = 0;i < list->nodesetval->nodeNr;i++) {
1140: if (dir)
1141: xmlShellDir(ctxt, NULL,
1142: list->nodesetval->nodeTab[i], NULL);
1143: else
1144: xmlShellList(ctxt, NULL,
1145: list->nodesetval->nodeTab[i], NULL);
1146: }
1147: break;
1148: }
1149: case XPATH_BOOLEAN:
1150: fprintf(stderr, "%s is a Boolean\n", arg);
1151: break;
1152: case XPATH_NUMBER:
1153: fprintf(stderr, "%s is a number\n", arg);
1154: break;
1155: case XPATH_STRING:
1156: fprintf(stderr, "%s is a string\n", arg);
1157: break;
1158: }
1159: xmlXPathFreeNodeSetList(list);
1160: } else {
1161: fprintf(stderr, "%s: no such node\n", arg);
1162: }
1163: if (ctxt->pctxt->nodelist != NULL)
1164: xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
1165: ctxt->pctxt->nodelist = NULL;
1166: }
1167: } else if (!strcmp(command, "cd")) {
1168: if (arg[0] == 0) {
1169: ctxt->node = (xmlNodePtr) ctxt->doc;
1170: } else {
1171: ctxt->pctxt->node = ctxt->node;
1172: if (ctxt->pctxt->nodelist != NULL)
1173: xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
1174: ctxt->pctxt->nodelist = xmlXPathNodeSetCreate(ctxt->node);
1175: list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
1176: if (list != NULL) {
1177: switch (list->type) {
1178: case XPATH_UNDEFINED:
1179: fprintf(stderr, "%s: no such node\n", arg);
1180: break;
1181: case XPATH_NODESET:
1182: if (list->nodesetval->nodeNr == 1) {
1183: ctxt->node = list->nodesetval->nodeTab[0];
1184: } else
1185: fprintf(stderr, "%s is a %d Node Set\n",
1186: arg, list->nodesetval->nodeNr);
1187: break;
1188: case XPATH_BOOLEAN:
1189: fprintf(stderr, "%s is a Boolean\n", arg);
1190: break;
1191: case XPATH_NUMBER:
1192: fprintf(stderr, "%s is a number\n", arg);
1193: break;
1194: case XPATH_STRING:
1195: fprintf(stderr, "%s is a string\n", arg);
1196: break;
1197: }
1198: xmlXPathFreeNodeSetList(list);
1199: } else {
1200: fprintf(stderr, "%s: no such node\n", arg);
1201: }
1202: if (ctxt->pctxt->nodelist != NULL)
1203: xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
1204: ctxt->pctxt->nodelist = NULL;
1205: }
1206: } else if (!strcmp(command, "cat")) {
1207: if (arg[0] == 0) {
1208: xmlShellCat(ctxt, NULL, ctxt->node, NULL);
1209: } else {
1210: ctxt->pctxt->node = ctxt->node;
1211: if (ctxt->pctxt->nodelist != NULL)
1212: xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
1213: ctxt->pctxt->nodelist = xmlXPathNodeSetCreate(ctxt->node);
1214: list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
1215: if (list != NULL) {
1216: switch (list->type) {
1217: case XPATH_UNDEFINED:
1218: fprintf(stderr, "%s: no such node\n", arg);
1219: break;
1220: case XPATH_NODESET: {
1221: int i;
1222:
1223: for (i = 0;i < list->nodesetval->nodeNr;i++) {
1224: if (i > 0) printf(" -------\n");
1225: xmlShellCat(ctxt, NULL,
1226: list->nodesetval->nodeTab[i], NULL);
1227: }
1228: break;
1229: }
1230: case XPATH_BOOLEAN:
1231: fprintf(stderr, "%s is a Boolean\n", arg);
1232: break;
1233: case XPATH_NUMBER:
1234: fprintf(stderr, "%s is a number\n", arg);
1235: break;
1236: case XPATH_STRING:
1237: fprintf(stderr, "%s is a string\n", arg);
1238: break;
1239: }
1240: xmlXPathFreeNodeSetList(list);
1241: } else {
1242: fprintf(stderr, "%s: no such node\n", arg);
1243: }
1244: if (ctxt->pctxt->nodelist != NULL)
1245: xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
1246: ctxt->pctxt->nodelist = NULL;
1247: }
1248: } else {
1249: fprintf(stderr, "Unknown command %s\n", command);
1250: }
1251: free(cmdline); /* not xmlFree here ! */
1252: }
1253: xmlXPathFreeContext(ctxt->pctxt);
1254: if (ctxt->loaded) {
1255: xmlFreeDoc(ctxt->doc);
1256: }
1257: xmlFree(ctxt);
1258: if (cmdline != NULL)
1259: free(cmdline); /* not xmlFree here ! */
1260: }
1261:
Webmaster