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