2 * xmlsave.c: Implemetation of the document serializer
4 * See Copyright for the status of this software.
13 #include <libxml/xmlmemory.h>
14 #include <libxml/parserInternals.h>
15 #include <libxml/tree.h>
16 #include <libxml/xmlsave.h>
20 #include <libxml/HTMLtree.h>
22 /************************************************************************
26 ************************************************************************/
27 #define XHTML_STRICT_PUBLIC_ID BAD_CAST \
28 "-//W3C//DTD XHTML 1.0 Strict//EN"
29 #define XHTML_STRICT_SYSTEM_ID BAD_CAST \
30 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
31 #define XHTML_FRAME_PUBLIC_ID BAD_CAST \
32 "-//W3C//DTD XHTML 1.0 Frameset//EN"
33 #define XHTML_FRAME_SYSTEM_ID BAD_CAST \
34 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
35 #define XHTML_TRANS_PUBLIC_ID BAD_CAST \
36 "-//W3C//DTD XHTML 1.0 Transitional//EN"
37 #define XHTML_TRANS_SYSTEM_ID BAD_CAST \
38 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
40 #define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
43 * @systemID: the system identifier
44 * @publicID: the public identifier
46 * Try to find if the document correspond to an XHTML DTD
48 * Returns 1 if true, 0 if not and -1 in case of error
51 xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
52 if ((systemID == NULL) && (publicID == NULL))
54 if (publicID != NULL) {
55 if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
56 if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
57 if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
59 if (systemID != NULL) {
60 if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
61 if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
62 if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
67 #ifdef LIBXML_OUTPUT_ENABLED
70 xmlGenericError(xmlGenericErrorContext, \
71 "Unimplemented block at %s:%d\n", \
78 const xmlChar *filename;
79 const xmlChar *encoding;
80 xmlCharEncodingHandlerPtr handler;
81 xmlOutputBufferPtr buf;
86 char indent[MAX_INDENT + 1]; /* array for indenting output */
89 xmlCharEncodingOutputFunc escape; /* used for element content */
90 xmlCharEncodingOutputFunc escapeAttr;/* used for attribute content */
93 /************************************************************************
95 * Output error handlers *
97 ************************************************************************/
100 * @extra: extra informations
102 * Handle an out of memory condition
105 xmlSaveErrMemory(const char *extra)
107 __xmlSimpleError(XML_FROM_OUTPUT, XML_ERR_NO_MEMORY, NULL, NULL, extra);
112 * @code: the error number
113 * @node: the location of the error.
114 * @extra: extra informations
116 * Handle an out of memory condition
119 xmlSaveErr(int code, xmlNodePtr node, const char *extra)
121 const char *msg = NULL;
124 case XML_SAVE_NOT_UTF8:
125 msg = "string is not in UTF-8\n";
127 case XML_SAVE_CHAR_INVALID:
128 msg = "invalid character value\n";
130 case XML_SAVE_UNKNOWN_ENCODING:
131 msg = "unknown encoding %s\n";
133 case XML_SAVE_NO_DOCTYPE:
134 msg = "document has no DOCTYPE\n";
137 msg = "unexpected error number\n";
139 __xmlSimpleError(XML_FROM_OUTPUT, code, node, msg, extra);
142 /************************************************************************
144 * Special escaping routines *
146 ************************************************************************/
147 static unsigned char *
148 xmlSerializeHexCharRef(unsigned char *out, int val) {
154 if (val < 0x10) ptr = out;
155 else if (val < 0x100) ptr = out + 1;
156 else if (val < 0x1000) ptr = out + 2;
157 else if (val < 0x10000) ptr = out + 3;
158 else if (val < 0x100000) ptr = out + 4;
163 case 0: *ptr-- = '0'; break;
164 case 1: *ptr-- = '1'; break;
165 case 2: *ptr-- = '2'; break;
166 case 3: *ptr-- = '3'; break;
167 case 4: *ptr-- = '4'; break;
168 case 5: *ptr-- = '5'; break;
169 case 6: *ptr-- = '6'; break;
170 case 7: *ptr-- = '7'; break;
171 case 8: *ptr-- = '8'; break;
172 case 9: *ptr-- = '9'; break;
173 case 0xA: *ptr-- = 'A'; break;
174 case 0xB: *ptr-- = 'B'; break;
175 case 0xC: *ptr-- = 'C'; break;
176 case 0xD: *ptr-- = 'D'; break;
177 case 0xE: *ptr-- = 'E'; break;
178 case 0xF: *ptr-- = 'F'; break;
179 default: *ptr-- = '0'; break;
190 * @out: a pointer to an array of bytes to store the result
191 * @outlen: the length of @out
192 * @in: a pointer to an array of unescaped UTF-8 bytes
193 * @inlen: the length of @in
195 * Take a block of UTF-8 chars in and escape them. Used when there is no
196 * encoding specified.
198 * Returns 0 if success, or -1 otherwise
199 * The value of @inlen after return is the number of octets consumed
200 * if the return value is positive, else unpredictable.
201 * The value of @outlen after return is the number of octets consumed.
204 xmlEscapeEntities(unsigned char* out, int *outlen,
205 const xmlChar* in, int *inlen) {
206 unsigned char* outstart = out;
207 const unsigned char* base = in;
208 unsigned char* outend = out + *outlen;
209 const unsigned char* inend;
212 inend = in + (*inlen);
214 while ((in < inend) && (out < outend)) {
216 if (outend - out < 4) break;
223 } else if (*in == '>') {
224 if (outend - out < 4) break;
231 } else if (*in == '&') {
232 if (outend - out < 5) break;
240 } else if (((*in >= 0x20) && (*in < 0x80)) ||
241 (*in == '\n') || (*in == '\t')) {
243 * default case, just copy !
247 } else if (*in >= 0x80) {
249 * We assume we have UTF-8 input.
251 if (outend - out < 11) break;
254 xmlSaveErr(XML_SAVE_NOT_UTF8, NULL, NULL);
257 } else if (*in < 0xE0) {
258 if (inend - in < 2) break;
259 val = (in[0]) & 0x1F;
261 val |= (in[1]) & 0x3F;
263 } else if (*in < 0xF0) {
264 if (inend - in < 3) break;
265 val = (in[0]) & 0x0F;
267 val |= (in[1]) & 0x3F;
269 val |= (in[2]) & 0x3F;
271 } else if (*in < 0xF8) {
272 if (inend - in < 4) break;
273 val = (in[0]) & 0x07;
275 val |= (in[1]) & 0x3F;
277 val |= (in[2]) & 0x3F;
279 val |= (in[3]) & 0x3F;
282 xmlSaveErr(XML_SAVE_CHAR_INVALID, NULL, NULL);
287 xmlSaveErr(XML_SAVE_CHAR_INVALID, NULL, NULL);
293 * We could do multiple things here. Just save as a char ref
295 out = xmlSerializeHexCharRef(out, val);
296 } else if (IS_BYTE_CHAR(*in)) {
297 if (outend - out < 6) break;
298 out = xmlSerializeHexCharRef(out, *in++);
300 xmlGenericError(xmlGenericErrorContext,
301 "xmlEscapeEntities : char out of range\n");
306 *outlen = out - outstart;
310 *outlen = out - outstart;
315 /************************************************************************
317 * Allocation and deallocation *
319 ************************************************************************/
322 * @ctxt: the saving context
324 * Initialize a saving context
327 xmlSaveCtxtInit(xmlSaveCtxtPtr ctxt)
332 if (ctxt == NULL) return;
333 if ((ctxt->encoding == NULL) && (ctxt->escape == NULL))
334 ctxt->escape = xmlEscapeEntities;
335 len = xmlStrlen((xmlChar *)xmlTreeIndentString);
336 if ((xmlTreeIndentString == NULL) || (len == 0)) {
337 memset(&ctxt->indent[0], 0, MAX_INDENT + 1);
339 ctxt->indent_size = len;
340 ctxt->indent_nr = MAX_INDENT / ctxt->indent_size;
341 for (i = 0;i < ctxt->indent_nr;i++)
342 memcpy(&ctxt->indent[i * ctxt->indent_size], xmlTreeIndentString,
344 ctxt->indent[ctxt->indent_nr * ctxt->indent_size] = 0;
347 if (xmlSaveNoEmptyTags) {
348 ctxt->options |= XML_SAVE_NO_EMPTY;
355 * Free a saving context, destroying the ouptut in any remaining buffer
358 xmlFreeSaveCtxt(xmlSaveCtxtPtr ctxt)
360 if (ctxt == NULL) return;
361 if (ctxt->encoding != NULL)
362 xmlFree((char *) ctxt->encoding);
363 if (ctxt->buf != NULL)
364 xmlOutputBufferClose(ctxt->buf);
371 * Create a new saving context
373 * Returns the new structure or NULL in case of error
375 static xmlSaveCtxtPtr
376 xmlNewSaveCtxt(const char *encoding, int options)
380 ret = (xmlSaveCtxtPtr) xmlMalloc(sizeof(xmlSaveCtxt));
382 xmlSaveErrMemory("creating saving context");
385 memset(ret, 0, sizeof(xmlSaveCtxt));
387 if (encoding != NULL) {
388 ret->handler = xmlFindCharEncodingHandler(encoding);
389 if (ret->handler == NULL) {
390 xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding);
391 xmlFreeSaveCtxt(ret);
394 ret->encoding = xmlStrdup((const xmlChar *)encoding);
397 xmlSaveCtxtInit(ret);
403 /* Re-check this option as it may already have been set */
404 if ((ret->options & XML_SAVE_NO_EMPTY) && ! (options & XML_SAVE_NO_EMPTY)) {
405 options |= XML_SAVE_NO_EMPTY;
408 ret->options = options;
409 if (options & XML_SAVE_FORMAT)
415 /************************************************************************
417 * Dumping XML tree content to a simple buffer *
419 ************************************************************************/
421 * xmlAttrSerializeContent:
422 * @buf: the XML buffer output
424 * @attr: the attribute pointer
426 * Serialize the attribute in the buffer
429 xmlAttrSerializeContent(xmlOutputBufferPtr buf, xmlAttrPtr attr)
433 children = attr->children;
434 while (children != NULL) {
435 switch (children->type) {
437 xmlAttrSerializeTxtContent(buf->buffer, attr->doc,
438 attr, children->content);
440 case XML_ENTITY_REF_NODE:
441 xmlBufferAdd(buf->buffer, BAD_CAST "&", 1);
442 xmlBufferAdd(buf->buffer, children->name,
443 xmlStrlen(children->name));
444 xmlBufferAdd(buf->buffer, BAD_CAST ";", 1);
447 /* should not happen unless we have a badly built tree */
450 children = children->next;
454 /************************************************************************
456 * Dumping XML tree content to an I/O output buffer *
458 ************************************************************************/
460 static int xmlSaveSwitchEncoding(xmlSaveCtxtPtr ctxt, const char *encoding) {
461 xmlOutputBufferPtr buf = ctxt->buf;
463 if ((encoding != NULL) && (buf->encoder == NULL) && (buf->conv == NULL)) {
464 buf->encoder = xmlFindCharEncodingHandler((const char *)encoding);
465 if (buf->encoder == NULL) {
466 xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL,
467 (const char *)encoding);
470 buf->conv = xmlBufferCreate();
471 if (buf->conv == NULL) {
472 xmlCharEncCloseFunc(buf->encoder);
473 xmlSaveErrMemory("creating encoding buffer");
477 * initialize the state, e.g. if outputting a BOM
479 xmlCharEncOutFunc(buf->encoder, buf->conv, NULL);
484 static int xmlSaveClearEncoding(xmlSaveCtxtPtr ctxt) {
485 xmlOutputBufferPtr buf = ctxt->buf;
486 xmlOutputBufferFlush(buf);
487 xmlCharEncCloseFunc(buf->encoder);
488 xmlBufferFree(buf->conv);
494 #ifdef LIBXML_HTML_ENABLED
496 xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);
498 static void xmlNodeListDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);
499 static void xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);
500 void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
501 static int xmlDocContentDumpOutput(xmlSaveCtxtPtr ctxt, xmlDocPtr cur);
505 * @buf: the XML buffer output
508 * Dump a local Namespace definition.
509 * Should be called in the context of attributes dumps.
512 xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
513 if ((cur == NULL) || (buf == NULL)) return;
514 if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
515 if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
518 /* Within the context of an element attributes */
519 if (cur->prefix != NULL) {
520 xmlOutputBufferWrite(buf, 7, " xmlns:");
521 xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
523 xmlOutputBufferWrite(buf, 6, " xmlns");
524 xmlOutputBufferWrite(buf, 1, "=");
525 xmlBufferWriteQuotedString(buf->buffer, cur->href);
530 * xmlNsListDumpOutput:
531 * @buf: the XML buffer output
532 * @cur: the first namespace
534 * Dump a list of local Namespace definitions.
535 * Should be called in the context of attributes dumps.
538 xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
539 while (cur != NULL) {
540 xmlNsDumpOutput(buf, cur);
547 * @buf: the XML buffer output
548 * @dtd: the pointer to the DTD
550 * Dump the XML document DTD, if any.
553 xmlDtdDumpOutput(xmlSaveCtxtPtr ctxt, xmlDtdPtr dtd) {
554 xmlOutputBufferPtr buf;
558 if (dtd == NULL) return;
559 if ((ctxt == NULL) || (ctxt->buf == NULL))
562 xmlOutputBufferWrite(buf, 10, "<!DOCTYPE ");
563 xmlOutputBufferWriteString(buf, (const char *)dtd->name);
564 if (dtd->ExternalID != NULL) {
565 xmlOutputBufferWrite(buf, 8, " PUBLIC ");
566 xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
567 xmlOutputBufferWrite(buf, 1, " ");
568 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
569 } else if (dtd->SystemID != NULL) {
570 xmlOutputBufferWrite(buf, 8, " SYSTEM ");
571 xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
573 if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
574 (dtd->attributes == NULL) && (dtd->notations == NULL) &&
575 (dtd->pentities == NULL)) {
576 xmlOutputBufferWrite(buf, 1, ">");
579 xmlOutputBufferWrite(buf, 3, " [\n");
581 * Dump the notations first they are not in the DTD children list
582 * Do this only on a standalone DTD or on the internal subset though.
584 if ((dtd->notations != NULL) && ((dtd->doc == NULL) ||
585 (dtd->doc->intSubset == dtd))) {
586 xmlDumpNotationTable(buf->buffer, (xmlNotationTablePtr) dtd->notations);
588 format = ctxt->format;
593 ctxt->doc = dtd->doc;
594 xmlNodeListDumpOutput(ctxt, dtd->children);
595 ctxt->format = format;
598 xmlOutputBufferWrite(buf, 2, "]>");
603 * @buf: the XML buffer output
604 * @cur: the attribute pointer
606 * Dump an XML attribute
609 xmlAttrDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) {
610 xmlOutputBufferPtr buf;
612 if (cur == NULL) return;
614 if (buf == NULL) return;
615 xmlOutputBufferWrite(buf, 1, " ");
616 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
617 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
618 xmlOutputBufferWrite(buf, 1, ":");
620 xmlOutputBufferWriteString(buf, (const char *)cur->name);
621 xmlOutputBufferWrite(buf, 2, "=\"");
622 xmlAttrSerializeContent(buf, cur);
623 xmlOutputBufferWrite(buf, 1, "\"");
627 * xmlAttrListDumpOutput:
628 * @buf: the XML buffer output
630 * @cur: the first attribute pointer
631 * @encoding: an optional encoding string
633 * Dump a list of XML attributes
636 xmlAttrListDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) {
637 if (cur == NULL) return;
638 while (cur != NULL) {
639 xmlAttrDumpOutput(ctxt, cur);
647 * xmlNodeListDumpOutput:
648 * @cur: the first node
650 * Dump an XML node list, recursive behaviour, children are printed too.
653 xmlNodeListDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
654 xmlOutputBufferPtr buf;
656 if (cur == NULL) return;
658 while (cur != NULL) {
659 if ((ctxt->format) && (xmlIndentTreeOutput) &&
660 ((cur->type == XML_ELEMENT_NODE) ||
661 (cur->type == XML_COMMENT_NODE) ||
662 (cur->type == XML_PI_NODE)))
663 xmlOutputBufferWrite(buf, ctxt->indent_size *
664 (ctxt->level > ctxt->indent_nr ?
665 ctxt->indent_nr : ctxt->level),
667 xmlNodeDumpOutputInternal(ctxt, cur);
669 xmlOutputBufferWrite(buf, 1, "\n");
675 #ifdef LIBXML_HTML_ENABLED
677 * xmlNodeDumpOutputInternal:
678 * @cur: the current node
680 * Dump an HTML node, recursive behaviour, children are printed too.
683 htmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
684 const xmlChar *oldenc = NULL;
685 const xmlChar *oldctxtenc = ctxt->encoding;
686 const xmlChar *encoding = ctxt->encoding;
687 xmlOutputBufferPtr buf = ctxt->buf;
688 int switched_encoding = 0;
695 oldenc = doc->encoding;
696 if (ctxt->encoding != NULL) {
697 doc->encoding = BAD_CAST ctxt->encoding;
698 } else if (doc->encoding != NULL) {
699 encoding = doc->encoding;
703 if ((encoding != NULL) && (doc != NULL))
704 htmlSetMetaEncoding(doc, (const xmlChar *) encoding);
705 if ((encoding == NULL) && (doc != NULL))
706 encoding = htmlGetMetaEncoding(doc);
707 if (encoding == NULL)
708 encoding = BAD_CAST "HTML";
709 if ((encoding != NULL) && (oldctxtenc == NULL) &&
710 (buf->encoder == NULL) && (buf->conv == NULL)) {
711 if (xmlSaveSwitchEncoding(ctxt, (const char*) encoding) < 0) {
712 doc->encoding = oldenc;
715 switched_encoding = 1;
717 if (ctxt->options & XML_SAVE_FORMAT)
718 htmlNodeDumpFormatOutput(buf, doc, cur,
719 (const char *)encoding, 1);
721 htmlNodeDumpFormatOutput(buf, doc, cur,
722 (const char *)encoding, 0);
724 * Restore the state of the saving context at the end of the document
726 if ((switched_encoding) && (oldctxtenc == NULL)) {
727 xmlSaveClearEncoding(ctxt);
730 doc->encoding = oldenc;
736 * xmlNodeDumpOutputInternal:
737 * @cur: the current node
739 * Dump an XML node, recursive behaviour, children are printed too.
742 xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
745 xmlChar *start, *end;
746 xmlOutputBufferPtr buf;
748 if (cur == NULL) return;
750 if (cur->type == XML_XINCLUDE_START)
752 if (cur->type == XML_XINCLUDE_END)
754 if ((cur->type == XML_DOCUMENT_NODE) ||
755 (cur->type == XML_HTML_DOCUMENT_NODE)) {
756 xmlDocContentDumpOutput(ctxt, (xmlDocPtr) cur);
759 #ifdef LIBXML_HTML_ENABLED
760 if (ctxt->options & XML_SAVE_XHTML) {
761 xhtmlNodeDumpOutput(ctxt, cur);
764 if (((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL) &&
765 (cur->doc->type == XML_HTML_DOCUMENT_NODE) &&
766 ((ctxt->options & XML_SAVE_AS_XML) == 0)) ||
767 (ctxt->options & XML_SAVE_AS_HTML)) {
768 htmlNodeDumpOutputInternal(ctxt, cur);
772 if (cur->type == XML_DTD_NODE) {
773 xmlDtdDumpOutput(ctxt, (xmlDtdPtr) cur);
776 if (cur->type == XML_DOCUMENT_FRAG_NODE) {
777 xmlNodeListDumpOutput(ctxt, cur->children);
780 if (cur->type == XML_ELEMENT_DECL) {
781 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
784 if (cur->type == XML_ATTRIBUTE_DECL) {
785 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
788 if (cur->type == XML_ENTITY_DECL) {
789 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
792 if (cur->type == XML_TEXT_NODE) {
793 if (cur->content != NULL) {
794 if (cur->name != xmlStringTextNoenc) {
795 xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape);
798 * Disable escaping, needed for XSLT
800 xmlOutputBufferWriteString(buf, (const char *) cur->content);
806 if (cur->type == XML_PI_NODE) {
807 if (cur->content != NULL) {
808 xmlOutputBufferWrite(buf, 2, "<?");
809 xmlOutputBufferWriteString(buf, (const char *)cur->name);
810 if (cur->content != NULL) {
811 xmlOutputBufferWrite(buf, 1, " ");
812 xmlOutputBufferWriteString(buf, (const char *)cur->content);
814 xmlOutputBufferWrite(buf, 2, "?>");
816 xmlOutputBufferWrite(buf, 2, "<?");
817 xmlOutputBufferWriteString(buf, (const char *)cur->name);
818 xmlOutputBufferWrite(buf, 2, "?>");
822 if (cur->type == XML_COMMENT_NODE) {
823 if (cur->content != NULL) {
824 xmlOutputBufferWrite(buf, 4, "<!--");
825 xmlOutputBufferWriteString(buf, (const char *)cur->content);
826 xmlOutputBufferWrite(buf, 3, "-->");
830 if (cur->type == XML_ENTITY_REF_NODE) {
831 xmlOutputBufferWrite(buf, 1, "&");
832 xmlOutputBufferWriteString(buf, (const char *)cur->name);
833 xmlOutputBufferWrite(buf, 1, ";");
836 if (cur->type == XML_CDATA_SECTION_NODE) {
837 if (cur->content == NULL || *cur->content == '\0') {
838 xmlOutputBufferWrite(buf, 12, "<![CDATA[]]>");
840 start = end = cur->content;
841 while (*end != '\0') {
842 if ((*end == ']') && (*(end + 1) == ']') &&
843 (*(end + 2) == '>')) {
845 xmlOutputBufferWrite(buf, 9, "<![CDATA[");
846 xmlOutputBufferWrite(buf, end - start, (const char *)start);
847 xmlOutputBufferWrite(buf, 3, "]]>");
853 xmlOutputBufferWrite(buf, 9, "<![CDATA[");
854 xmlOutputBufferWriteString(buf, (const char *)start);
855 xmlOutputBufferWrite(buf, 3, "]]>");
860 if (cur->type == XML_ATTRIBUTE_NODE) {
861 xmlAttrDumpOutput(ctxt, (xmlAttrPtr) cur);
864 if (cur->type == XML_NAMESPACE_DECL) {
865 xmlNsDumpOutput(buf, (xmlNsPtr) cur);
869 format = ctxt->format;
872 while (tmp != NULL) {
873 if ((tmp->type == XML_TEXT_NODE) ||
874 (tmp->type == XML_CDATA_SECTION_NODE) ||
875 (tmp->type == XML_ENTITY_REF_NODE)) {
882 xmlOutputBufferWrite(buf, 1, "<");
883 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
884 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
885 xmlOutputBufferWrite(buf, 1, ":");
888 xmlOutputBufferWriteString(buf, (const char *)cur->name);
890 xmlNsListDumpOutput(buf, cur->nsDef);
891 if (cur->properties != NULL)
892 xmlAttrListDumpOutput(ctxt, cur->properties);
894 if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
895 (cur->children == NULL) && ((ctxt->options & XML_SAVE_NO_EMPTY) == 0)) {
896 xmlOutputBufferWrite(buf, 2, "/>");
897 ctxt->format = format;
900 xmlOutputBufferWrite(buf, 1, ">");
901 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
902 xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape);
904 if (cur->children != NULL) {
905 if (ctxt->format) xmlOutputBufferWrite(buf, 1, "\n");
906 if (ctxt->level >= 0) ctxt->level++;
907 xmlNodeListDumpOutput(ctxt, cur->children);
908 if (ctxt->level > 0) ctxt->level--;
909 if ((xmlIndentTreeOutput) && (ctxt->format))
910 xmlOutputBufferWrite(buf, ctxt->indent_size *
911 (ctxt->level > ctxt->indent_nr ?
912 ctxt->indent_nr : ctxt->level),
915 xmlOutputBufferWrite(buf, 2, "</");
916 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
917 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
918 xmlOutputBufferWrite(buf, 1, ":");
921 xmlOutputBufferWriteString(buf, (const char *)cur->name);
922 xmlOutputBufferWrite(buf, 1, ">");
923 ctxt->format = format;
927 * xmlDocContentDumpOutput:
930 * Dump an XML document.
933 xmlDocContentDumpOutput(xmlSaveCtxtPtr ctxt, xmlDocPtr cur) {
934 #ifdef LIBXML_HTML_ENABLED
938 const xmlChar *oldenc = cur->encoding;
939 const xmlChar *oldctxtenc = ctxt->encoding;
940 const xmlChar *encoding = ctxt->encoding;
941 xmlCharEncodingOutputFunc oldescape = ctxt->escape;
942 xmlCharEncodingOutputFunc oldescapeAttr = ctxt->escapeAttr;
943 xmlOutputBufferPtr buf = ctxt->buf;
945 int switched_encoding = 0;
949 if ((cur->type != XML_HTML_DOCUMENT_NODE) &&
950 (cur->type != XML_DOCUMENT_NODE))
953 if (ctxt->encoding != NULL) {
954 cur->encoding = BAD_CAST ctxt->encoding;
955 } else if (cur->encoding != NULL) {
956 encoding = cur->encoding;
957 } else if (cur->charset != XML_CHAR_ENCODING_UTF8) {
958 encoding = (const xmlChar *)
959 xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
962 if (((cur->type == XML_HTML_DOCUMENT_NODE) &&
963 ((ctxt->options & XML_SAVE_AS_XML) == 0) &&
964 ((ctxt->options & XML_SAVE_XHTML) == 0)) ||
965 (ctxt->options & XML_SAVE_AS_HTML)) {
966 #ifdef LIBXML_HTML_ENABLED
967 if (encoding != NULL)
968 htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
969 if (encoding == NULL)
970 encoding = htmlGetMetaEncoding(cur);
971 if (encoding == NULL)
972 encoding = BAD_CAST "HTML";
973 if ((encoding != NULL) && (oldctxtenc == NULL) &&
974 (buf->encoder == NULL) && (buf->conv == NULL)) {
975 if (xmlSaveSwitchEncoding(ctxt, (const char*) encoding) < 0) {
976 cur->encoding = oldenc;
980 if (ctxt->options & XML_SAVE_FORMAT)
981 htmlDocContentDumpFormatOutput(buf, cur,
982 (const char *)encoding, 1);
984 htmlDocContentDumpFormatOutput(buf, cur,
985 (const char *)encoding, 0);
986 if (ctxt->encoding != NULL)
987 cur->encoding = oldenc;
992 } else if ((cur->type == XML_DOCUMENT_NODE) ||
993 (ctxt->options & XML_SAVE_AS_XML) ||
994 (ctxt->options & XML_SAVE_XHTML)) {
995 enc = xmlParseCharEncoding((const char*) encoding);
996 if ((encoding != NULL) && (oldctxtenc == NULL) &&
997 (buf->encoder == NULL) && (buf->conv == NULL) &&
998 ((ctxt->options & XML_SAVE_NO_DECL) == 0)) {
999 if ((enc != XML_CHAR_ENCODING_UTF8) &&
1000 (enc != XML_CHAR_ENCODING_NONE) &&
1001 (enc != XML_CHAR_ENCODING_ASCII)) {
1003 * we need to switch to this encoding but just for this
1004 * document since we output the XMLDecl the conversion
1005 * must be done to not generate not well formed documents.
1007 if (xmlSaveSwitchEncoding(ctxt, (const char*) encoding) < 0) {
1008 cur->encoding = oldenc;
1011 switched_encoding = 1;
1013 if (ctxt->escape == xmlEscapeEntities)
1014 ctxt->escape = NULL;
1015 if (ctxt->escapeAttr == xmlEscapeEntities)
1016 ctxt->escapeAttr = NULL;
1021 * Save the XML declaration
1023 if ((ctxt->options & XML_SAVE_NO_DECL) == 0) {
1024 xmlOutputBufferWrite(buf, 14, "<?xml version=");
1025 if (cur->version != NULL)
1026 xmlBufferWriteQuotedString(buf->buffer, cur->version);
1028 xmlOutputBufferWrite(buf, 5, "\"1.0\"");
1029 if (encoding != NULL) {
1030 xmlOutputBufferWrite(buf, 10, " encoding=");
1031 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
1033 switch (cur->standalone) {
1035 xmlOutputBufferWrite(buf, 16, " standalone=\"no\"");
1038 xmlOutputBufferWrite(buf, 17, " standalone=\"yes\"");
1041 xmlOutputBufferWrite(buf, 3, "?>\n");
1044 #ifdef LIBXML_HTML_ENABLED
1045 if (ctxt->options & XML_SAVE_XHTML)
1047 if ((ctxt->options & XML_SAVE_NO_XHTML) == 0) {
1048 dtd = xmlGetIntSubset(cur);
1050 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
1051 if (is_xhtml < 0) is_xhtml = 0;
1055 if (cur->children != NULL) {
1056 xmlNodePtr child = cur->children;
1058 while (child != NULL) {
1060 #ifdef LIBXML_HTML_ENABLED
1062 xhtmlNodeDumpOutput(ctxt, child);
1065 xmlNodeDumpOutputInternal(ctxt, child);
1066 xmlOutputBufferWrite(buf, 1, "\n");
1067 child = child->next;
1073 * Restore the state of the saving context at the end of the document
1075 if ((switched_encoding) && (oldctxtenc == NULL)) {
1076 xmlSaveClearEncoding(ctxt);
1077 ctxt->escape = oldescape;
1078 ctxt->escapeAttr = oldescapeAttr;
1080 cur->encoding = oldenc;
1084 #ifdef LIBXML_HTML_ENABLED
1085 /************************************************************************
1087 * Functions specific to XHTML serialization *
1089 ************************************************************************/
1095 * Check if a node is an empty xhtml node
1097 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
1100 xhtmlIsEmpty(xmlNodePtr node) {
1103 if (node->type != XML_ELEMENT_NODE)
1105 if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
1107 if (node->children != NULL)
1109 switch (node->name[0]) {
1111 if (xmlStrEqual(node->name, BAD_CAST "area"))
1115 if (xmlStrEqual(node->name, BAD_CAST "br"))
1117 if (xmlStrEqual(node->name, BAD_CAST "base"))
1119 if (xmlStrEqual(node->name, BAD_CAST "basefont"))
1123 if (xmlStrEqual(node->name, BAD_CAST "col"))
1127 if (xmlStrEqual(node->name, BAD_CAST "frame"))
1131 if (xmlStrEqual(node->name, BAD_CAST "hr"))
1135 if (xmlStrEqual(node->name, BAD_CAST "img"))
1137 if (xmlStrEqual(node->name, BAD_CAST "input"))
1139 if (xmlStrEqual(node->name, BAD_CAST "isindex"))
1143 if (xmlStrEqual(node->name, BAD_CAST "link"))
1147 if (xmlStrEqual(node->name, BAD_CAST "meta"))
1151 if (xmlStrEqual(node->name, BAD_CAST "param"))
1159 * xhtmlAttrListDumpOutput:
1160 * @cur: the first attribute pointer
1162 * Dump a list of XML attributes
1165 xhtmlAttrListDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) {
1166 xmlAttrPtr xml_lang = NULL;
1167 xmlAttrPtr lang = NULL;
1168 xmlAttrPtr name = NULL;
1169 xmlAttrPtr id = NULL;
1171 xmlOutputBufferPtr buf;
1173 if (cur == NULL) return;
1175 parent = cur->parent;
1176 while (cur != NULL) {
1177 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
1180 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
1183 if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
1186 if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
1187 (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
1189 else if ((cur->ns == NULL) &&
1190 ((cur->children == NULL) ||
1191 (cur->children->content == NULL) ||
1192 (cur->children->content[0] == 0)) &&
1193 (htmlIsBooleanAttr(cur->name))) {
1194 if (cur->children != NULL)
1195 xmlFreeNode(cur->children);
1196 cur->children = xmlNewText(cur->name);
1197 if (cur->children != NULL)
1198 cur->children->parent = (xmlNodePtr) cur;
1200 xmlAttrDumpOutput(ctxt, cur);
1206 if ((name != NULL) && (id == NULL)) {
1207 if ((parent != NULL) && (parent->name != NULL) &&
1208 ((xmlStrEqual(parent->name, BAD_CAST "a")) ||
1209 (xmlStrEqual(parent->name, BAD_CAST "p")) ||
1210 (xmlStrEqual(parent->name, BAD_CAST "div")) ||
1211 (xmlStrEqual(parent->name, BAD_CAST "img")) ||
1212 (xmlStrEqual(parent->name, BAD_CAST "map")) ||
1213 (xmlStrEqual(parent->name, BAD_CAST "applet")) ||
1214 (xmlStrEqual(parent->name, BAD_CAST "form")) ||
1215 (xmlStrEqual(parent->name, BAD_CAST "frame")) ||
1216 (xmlStrEqual(parent->name, BAD_CAST "iframe")))) {
1217 xmlOutputBufferWrite(buf, 5, " id=\"");
1218 xmlAttrSerializeContent(buf, name);
1219 xmlOutputBufferWrite(buf, 1, "\"");
1225 if ((lang != NULL) && (xml_lang == NULL)) {
1226 xmlOutputBufferWrite(buf, 11, " xml:lang=\"");
1227 xmlAttrSerializeContent(buf, lang);
1228 xmlOutputBufferWrite(buf, 1, "\"");
1230 if ((xml_lang != NULL) && (lang == NULL)) {
1231 xmlOutputBufferWrite(buf, 7, " lang=\"");
1232 xmlAttrSerializeContent(buf, xml_lang);
1233 xmlOutputBufferWrite(buf, 1, "\"");
1238 * xhtmlNodeListDumpOutput:
1239 * @buf: the XML buffer output
1240 * @doc: the XHTML document
1241 * @cur: the first node
1242 * @level: the imbrication level for indenting
1243 * @format: is formatting allowed
1244 * @encoding: an optional encoding string
1246 * Dump an XML node list, recursive behaviour, children are printed too.
1247 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
1248 * or xmlKeepBlanksDefault(0) was called
1251 xhtmlNodeListDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
1252 xmlOutputBufferPtr buf;
1254 if (cur == NULL) return;
1256 while (cur != NULL) {
1257 if ((ctxt->format) && (xmlIndentTreeOutput) &&
1258 (cur->type == XML_ELEMENT_NODE))
1259 xmlOutputBufferWrite(buf, ctxt->indent_size *
1260 (ctxt->level > ctxt->indent_nr ?
1261 ctxt->indent_nr : ctxt->level),
1263 xhtmlNodeDumpOutput(ctxt, cur);
1265 xmlOutputBufferWrite(buf, 1, "\n");
1272 * xhtmlNodeDumpOutput:
1273 * @buf: the XML buffer output
1274 * @doc: the XHTML document
1275 * @cur: the current node
1276 * @level: the imbrication level for indenting
1277 * @format: is formatting allowed
1278 * @encoding: an optional encoding string
1280 * Dump an XHTML node, recursive behaviour, children are printed too.
1283 xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
1284 int format, addmeta = 0;
1286 xmlChar *start, *end;
1287 xmlOutputBufferPtr buf;
1289 if (cur == NULL) return;
1290 if ((cur->type == XML_DOCUMENT_NODE) ||
1291 (cur->type == XML_HTML_DOCUMENT_NODE)) {
1292 xmlDocContentDumpOutput(ctxt, (xmlDocPtr) cur);
1295 if (cur->type == XML_XINCLUDE_START)
1297 if (cur->type == XML_XINCLUDE_END)
1299 if (cur->type == XML_DTD_NODE) {
1300 xmlDtdDumpOutput(ctxt, (xmlDtdPtr) cur);
1303 if (cur->type == XML_DOCUMENT_FRAG_NODE) {
1304 xhtmlNodeListDumpOutput(ctxt, cur->children);
1308 if (cur->type == XML_ELEMENT_DECL) {
1309 xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
1312 if (cur->type == XML_ATTRIBUTE_DECL) {
1313 xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
1316 if (cur->type == XML_ENTITY_DECL) {
1317 xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
1320 if (cur->type == XML_TEXT_NODE) {
1321 if (cur->content != NULL) {
1322 if ((cur->name == xmlStringText) ||
1323 (cur->name != xmlStringTextNoenc)) {
1324 xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape);
1327 * Disable escaping, needed for XSLT
1329 xmlOutputBufferWriteString(buf, (const char *) cur->content);
1335 if (cur->type == XML_PI_NODE) {
1336 if (cur->content != NULL) {
1337 xmlOutputBufferWrite(buf, 2, "<?");
1338 xmlOutputBufferWriteString(buf, (const char *)cur->name);
1339 if (cur->content != NULL) {
1340 xmlOutputBufferWrite(buf, 1, " ");
1341 xmlOutputBufferWriteString(buf, (const char *)cur->content);
1343 xmlOutputBufferWrite(buf, 2, "?>");
1345 xmlOutputBufferWrite(buf, 2, "<?");
1346 xmlOutputBufferWriteString(buf, (const char *)cur->name);
1347 xmlOutputBufferWrite(buf, 2, "?>");
1351 if (cur->type == XML_COMMENT_NODE) {
1352 if (cur->content != NULL) {
1353 xmlOutputBufferWrite(buf, 4, "<!--");
1354 xmlOutputBufferWriteString(buf, (const char *)cur->content);
1355 xmlOutputBufferWrite(buf, 3, "-->");
1359 if (cur->type == XML_ENTITY_REF_NODE) {
1360 xmlOutputBufferWrite(buf, 1, "&");
1361 xmlOutputBufferWriteString(buf, (const char *)cur->name);
1362 xmlOutputBufferWrite(buf, 1, ";");
1365 if (cur->type == XML_CDATA_SECTION_NODE) {
1366 if (cur->content == NULL || *cur->content == '\0') {
1367 xmlOutputBufferWrite(buf, 12, "<![CDATA[]]>");
1369 start = end = cur->content;
1370 while (*end != '\0') {
1371 if (*end == ']' && *(end + 1) == ']' && *(end + 2) == '>') {
1373 xmlOutputBufferWrite(buf, 9, "<![CDATA[");
1374 xmlOutputBufferWrite(buf, end - start, (const char *)start);
1375 xmlOutputBufferWrite(buf, 3, "]]>");
1381 xmlOutputBufferWrite(buf, 9, "<![CDATA[");
1382 xmlOutputBufferWriteString(buf, (const char *)start);
1383 xmlOutputBufferWrite(buf, 3, "]]>");
1388 if (cur->type == XML_ATTRIBUTE_NODE) {
1389 xmlAttrDumpOutput(ctxt, (xmlAttrPtr) cur);
1393 format = ctxt->format;
1395 tmp = cur->children;
1396 while (tmp != NULL) {
1397 if ((tmp->type == XML_TEXT_NODE) ||
1398 (tmp->type == XML_ENTITY_REF_NODE)) {
1405 xmlOutputBufferWrite(buf, 1, "<");
1406 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
1407 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
1408 xmlOutputBufferWrite(buf, 1, ":");
1411 xmlOutputBufferWriteString(buf, (const char *)cur->name);
1413 xmlNsListDumpOutput(buf, cur->nsDef);
1414 if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
1415 (cur->ns == NULL) && (cur->nsDef == NULL))) {
1417 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
1419 xmlOutputBufferWriteString(buf,
1420 " xmlns=\"http://www.w3.org/1999/xhtml\"");
1422 if (cur->properties != NULL)
1423 xhtmlAttrListDumpOutput(ctxt, cur->properties);
1425 if ((cur->type == XML_ELEMENT_NODE) &&
1426 (cur->parent != NULL) &&
1427 (cur->parent->parent == (xmlNodePtr) cur->doc) &&
1428 xmlStrEqual(cur->name, BAD_CAST"head") &&
1429 xmlStrEqual(cur->parent->name, BAD_CAST"html")) {
1431 tmp = cur->children;
1432 while (tmp != NULL) {
1433 if (xmlStrEqual(tmp->name, BAD_CAST"meta")) {
1436 httpequiv = xmlGetProp(tmp, BAD_CAST"http-equiv");
1437 if (httpequiv != NULL) {
1438 if (xmlStrcasecmp(httpequiv, BAD_CAST"Content-Type") == 0) {
1451 if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
1452 if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
1453 ((xhtmlIsEmpty(cur) == 1) && (addmeta == 0))) {
1455 * C.2. Empty Elements
1457 xmlOutputBufferWrite(buf, 3, " />");
1460 xmlOutputBufferWrite(buf, 1, ">");
1462 xmlOutputBufferWrite(buf, 1, "\n");
1463 if (xmlIndentTreeOutput)
1464 xmlOutputBufferWrite(buf, ctxt->indent_size *
1465 (ctxt->level + 1 > ctxt->indent_nr ?
1466 ctxt->indent_nr : ctxt->level + 1), ctxt->indent);
1468 xmlOutputBufferWriteString(buf,
1469 "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=");
1470 if (ctxt->encoding) {
1471 xmlOutputBufferWriteString(buf, (const char *)ctxt->encoding);
1473 xmlOutputBufferWrite(buf, 5, "UTF-8");
1475 xmlOutputBufferWrite(buf, 4, "\" />");
1477 xmlOutputBufferWrite(buf, 1, "\n");
1479 xmlOutputBufferWrite(buf, 1, ">");
1482 * C.3. Element Minimization and Empty Element Content
1484 xmlOutputBufferWrite(buf, 2, "</");
1485 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
1486 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
1487 xmlOutputBufferWrite(buf, 1, ":");
1489 xmlOutputBufferWriteString(buf, (const char *)cur->name);
1490 xmlOutputBufferWrite(buf, 1, ">");
1494 xmlOutputBufferWrite(buf, 1, ">");
1497 xmlOutputBufferWrite(buf, 1, "\n");
1498 if (xmlIndentTreeOutput)
1499 xmlOutputBufferWrite(buf, ctxt->indent_size *
1500 (ctxt->level + 1 > ctxt->indent_nr ?
1501 ctxt->indent_nr : ctxt->level + 1), ctxt->indent);
1503 xmlOutputBufferWriteString(buf,
1504 "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=");
1505 if (ctxt->encoding) {
1506 xmlOutputBufferWriteString(buf, (const char *)ctxt->encoding);
1508 xmlOutputBufferWrite(buf, 5, "UTF-8");
1510 xmlOutputBufferWrite(buf, 4, "\" />");
1512 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
1513 xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape);
1518 * This was removed due to problems with HTML processors.
1522 * 4.8. Script and Style elements
1524 if ((cur->type == XML_ELEMENT_NODE) &&
1525 ((xmlStrEqual(cur->name, BAD_CAST "script")) ||
1526 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
1527 ((cur->ns == NULL) ||
1528 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
1529 xmlNodePtr child = cur->children;
1531 while (child != NULL) {
1532 if (child->type == XML_TEXT_NODE) {
1533 if ((xmlStrchr(child->content, '<') == NULL) &&
1534 (xmlStrchr(child->content, '&') == NULL) &&
1535 (xmlStrstr(child->content, BAD_CAST "]]>") == NULL)) {
1536 /* Nothing to escape, so just output as is... */
1537 /* FIXME: Should we do something about "--" also? */
1538 int level = ctxt->level;
1539 int indent = ctxt->format;
1543 xmlOutputBufferWriteString(buf, (const char *) child->content);
1544 /* (We cannot use xhtmlNodeDumpOutput() here because
1545 * we wish to leave '>' unescaped!) */
1546 ctxt->level = level;
1547 ctxt->format = indent;
1549 /* We must use a CDATA section. Unfortunately,
1550 * this will break CSS and JavaScript when read by
1551 * a browser in HTML4-compliant mode. :-( */
1552 start = end = child->content;
1553 while (*end != '\0') {
1555 *(end + 1) == ']' &&
1556 *(end + 2) == '>') {
1558 xmlOutputBufferWrite(buf, 9, "<![CDATA[");
1559 xmlOutputBufferWrite(buf, end - start,
1560 (const char *)start);
1561 xmlOutputBufferWrite(buf, 3, "]]>");
1567 xmlOutputBufferWrite(buf, 9, "<![CDATA[");
1568 xmlOutputBufferWrite(buf, end - start,
1569 (const char *)start);
1570 xmlOutputBufferWrite(buf, 3, "]]>");
1574 int level = ctxt->level;
1575 int indent = ctxt->format;
1579 xhtmlNodeDumpOutput(ctxt, child);
1580 ctxt->level = level;
1581 ctxt->format = indent;
1583 child = child->next;
1588 if (cur->children != NULL) {
1589 int indent = ctxt->format;
1591 if (format) xmlOutputBufferWrite(buf, 1, "\n");
1592 if (ctxt->level >= 0) ctxt->level++;
1593 ctxt->format = format;
1594 xhtmlNodeListDumpOutput(ctxt, cur->children);
1595 if (ctxt->level > 0) ctxt->level--;
1596 ctxt->format = indent;
1597 if ((xmlIndentTreeOutput) && (format))
1598 xmlOutputBufferWrite(buf, ctxt->indent_size *
1599 (ctxt->level > ctxt->indent_nr ?
1600 ctxt->indent_nr : ctxt->level),
1603 xmlOutputBufferWrite(buf, 2, "</");
1604 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
1605 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
1606 xmlOutputBufferWrite(buf, 1, ":");
1609 xmlOutputBufferWriteString(buf, (const char *)cur->name);
1610 xmlOutputBufferWrite(buf, 1, ">");
1614 /************************************************************************
1616 * Public entry points *
1618 ************************************************************************/
1622 * @fd: a file descriptor number
1623 * @encoding: the encoding name to use or NULL
1624 * @options: a set of xmlSaveOptions
1626 * Create a document saving context serializing to a file descriptor
1627 * with the encoding and the options given.
1629 * Returns a new serialization context or NULL in case of error.
1632 xmlSaveToFd(int fd, const char *encoding, int options)
1636 ret = xmlNewSaveCtxt(encoding, options);
1637 if (ret == NULL) return(NULL);
1638 ret->buf = xmlOutputBufferCreateFd(fd, ret->handler);
1639 if (ret->buf == NULL) {
1640 xmlFreeSaveCtxt(ret);
1647 * xmlSaveToFilename:
1648 * @filename: a file name or an URL
1649 * @encoding: the encoding name to use or NULL
1650 * @options: a set of xmlSaveOptions
1652 * Create a document saving context serializing to a filename or possibly
1653 * to an URL (but this is less reliable) with the encoding and the options
1656 * Returns a new serialization context or NULL in case of error.
1659 xmlSaveToFilename(const char *filename, const char *encoding, int options)
1662 int compression = 0; /* TODO handle compression option */
1664 ret = xmlNewSaveCtxt(encoding, options);
1665 if (ret == NULL) return(NULL);
1666 ret->buf = xmlOutputBufferCreateFilename(filename, ret->handler,
1668 if (ret->buf == NULL) {
1669 xmlFreeSaveCtxt(ret);
1678 * @encoding: the encoding name to use or NULL
1679 * @options: a set of xmlSaveOptions
1681 * Create a document saving context serializing to a buffer
1682 * with the encoding and the options given
1684 * Returns a new serialization context or NULL in case of error.
1688 xmlSaveToBuffer(xmlBufferPtr buffer, const char *encoding, int options)
1691 xmlOutputBufferPtr out_buff;
1692 xmlCharEncodingHandlerPtr handler;
1694 ret = xmlNewSaveCtxt(encoding, options);
1695 if (ret == NULL) return(NULL);
1697 if (encoding != NULL) {
1698 handler = xmlFindCharEncodingHandler(encoding);
1699 if (handler == NULL) {
1705 out_buff = xmlOutputBufferCreateBuffer(buffer, handler);
1706 if (out_buff == NULL) {
1708 if (handler) xmlCharEncCloseFunc(handler);
1712 ret->buf = out_buff;
1718 * @iowrite: an I/O write function
1719 * @ioclose: an I/O close function
1720 * @ioctx: an I/O handler
1721 * @encoding: the encoding name to use or NULL
1722 * @options: a set of xmlSaveOptions
1724 * Create a document saving context serializing to a file descriptor
1725 * with the encoding and the options given
1727 * Returns a new serialization context or NULL in case of error.
1730 xmlSaveToIO(xmlOutputWriteCallback iowrite,
1731 xmlOutputCloseCallback ioclose,
1732 void *ioctx, const char *encoding, int options)
1736 ret = xmlNewSaveCtxt(encoding, options);
1737 if (ret == NULL) return(NULL);
1738 ret->buf = xmlOutputBufferCreateIO(iowrite, ioclose, ioctx, ret->handler);
1739 if (ret->buf == NULL) {
1740 xmlFreeSaveCtxt(ret);
1748 * @ctxt: a document saving context
1751 * Save a full document to a saving context
1752 * TODO: The function is not fully implemented yet as it does not return the
1753 * byte count but 0 instead
1755 * Returns the number of byte written or -1 in case of error
1758 xmlSaveDoc(xmlSaveCtxtPtr ctxt, xmlDocPtr doc)
1762 if ((ctxt == NULL) || (doc == NULL)) return(-1);
1763 if (xmlDocContentDumpOutput(ctxt, doc) < 0)
1770 * @ctxt: a document saving context
1771 * @node: the top node of the subtree to save
1773 * Save a subtree starting at the node parameter to a saving context
1774 * TODO: The function is not fully implemented yet as it does not return the
1775 * byte count but 0 instead
1777 * Returns the number of byte written or -1 in case of error
1780 xmlSaveTree(xmlSaveCtxtPtr ctxt, xmlNodePtr node)
1784 if ((ctxt == NULL) || (node == NULL)) return(-1);
1785 xmlNodeDumpOutputInternal(ctxt, node);
1791 * @ctxt: a document saving context
1793 * Flush a document saving context, i.e. make sure that all bytes have
1796 * Returns the number of byte written or -1 in case of error.
1799 xmlSaveFlush(xmlSaveCtxtPtr ctxt)
1801 if (ctxt == NULL) return(-1);
1802 if (ctxt->buf == NULL) return(-1);
1803 return(xmlOutputBufferFlush(ctxt->buf));
1808 * @ctxt: a document saving context
1810 * Close a document saving context, i.e. make sure that all bytes have
1811 * been output and free the associated data.
1813 * Returns the number of byte written or -1 in case of error.
1816 xmlSaveClose(xmlSaveCtxtPtr ctxt)
1820 if (ctxt == NULL) return(-1);
1821 ret = xmlSaveFlush(ctxt);
1822 xmlFreeSaveCtxt(ctxt);
1828 * @ctxt: a document saving context
1829 * @escape: the escaping function
1831 * Set a custom escaping function to be used for text in element content
1833 * Returns 0 if successful or -1 in case of error.
1836 xmlSaveSetEscape(xmlSaveCtxtPtr ctxt, xmlCharEncodingOutputFunc escape)
1838 if (ctxt == NULL) return(-1);
1839 ctxt->escape = escape;
1844 * xmlSaveSetAttrEscape:
1845 * @ctxt: a document saving context
1846 * @escape: the escaping function
1848 * Set a custom escaping function to be used for text in attribute content
1850 * Returns 0 if successful or -1 in case of error.
1853 xmlSaveSetAttrEscape(xmlSaveCtxtPtr ctxt, xmlCharEncodingOutputFunc escape)
1855 if (ctxt == NULL) return(-1);
1856 ctxt->escapeAttr = escape;
1860 /************************************************************************
1862 * Public entry points based on buffers *
1864 ************************************************************************/
1866 * xmlAttrSerializeTxtContent:
1867 * @buf: the XML buffer output
1868 * @doc: the document
1869 * @attr: the attribute node
1870 * @string: the text content
1872 * Serialize text attribute values to an xml simple buffer
1875 xmlAttrSerializeTxtContent(xmlBufferPtr buf, xmlDocPtr doc,
1876 xmlAttrPtr attr, const xmlChar * string)
1878 xmlChar *base, *cur;
1882 base = cur = (xmlChar *) string;
1886 xmlBufferAdd(buf, base, cur - base);
1887 xmlBufferAdd(buf, BAD_CAST " ", 5);
1890 } else if (*cur == '\r') {
1892 xmlBufferAdd(buf, base, cur - base);
1893 xmlBufferAdd(buf, BAD_CAST " ", 5);
1896 } else if (*cur == '\t') {
1898 xmlBufferAdd(buf, base, cur - base);
1899 xmlBufferAdd(buf, BAD_CAST "	", 4);
1902 } else if (*cur == '"') {
1904 xmlBufferAdd(buf, base, cur - base);
1905 xmlBufferAdd(buf, BAD_CAST """, 6);
1908 } else if (*cur == '<') {
1910 xmlBufferAdd(buf, base, cur - base);
1911 xmlBufferAdd(buf, BAD_CAST "<", 4);
1914 } else if (*cur == '>') {
1916 xmlBufferAdd(buf, base, cur - base);
1917 xmlBufferAdd(buf, BAD_CAST ">", 4);
1920 } else if (*cur == '&') {
1922 xmlBufferAdd(buf, base, cur - base);
1923 xmlBufferAdd(buf, BAD_CAST "&", 5);
1926 } else if ((*cur >= 0x80) && ((doc == NULL) ||
1927 (doc->encoding == NULL))) {
1929 * We assume we have UTF-8 content.
1931 unsigned char tmp[12];
1935 xmlBufferAdd(buf, base, cur - base);
1937 xmlSaveErr(XML_SAVE_NOT_UTF8, (xmlNodePtr) attr, NULL);
1939 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
1940 xmlSerializeHexCharRef(tmp, *cur);
1941 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
1945 } else if (*cur < 0xE0) {
1946 val = (cur[0]) & 0x1F;
1948 val |= (cur[1]) & 0x3F;
1950 } else if (*cur < 0xF0) {
1951 val = (cur[0]) & 0x0F;
1953 val |= (cur[1]) & 0x3F;
1955 val |= (cur[2]) & 0x3F;
1957 } else if (*cur < 0xF8) {
1958 val = (cur[0]) & 0x07;
1960 val |= (cur[1]) & 0x3F;
1962 val |= (cur[2]) & 0x3F;
1964 val |= (cur[3]) & 0x3F;
1967 if ((l == 1) || (!IS_CHAR(val))) {
1968 xmlSaveErr(XML_SAVE_CHAR_INVALID, (xmlNodePtr) attr, NULL);
1970 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
1972 xmlSerializeHexCharRef(tmp, *cur);
1973 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
1979 * We could do multiple things here. Just save
1982 xmlSerializeHexCharRef(tmp, val);
1983 xmlBufferAdd(buf, (xmlChar *) tmp, -1);
1991 xmlBufferAdd(buf, base, cur - base);
1996 * @buf: the XML buffer output
1997 * @doc: the document
1998 * @cur: the current node
1999 * @level: the imbrication level for indenting
2000 * @format: is formatting allowed
2002 * Dump an XML node, recursive behaviour,children are printed too.
2003 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
2004 * or xmlKeepBlanksDefault(0) was called
2006 * Returns the number of bytes written to the buffer or -1 in case of error
2009 xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
2014 xmlOutputBufferPtr outbuf;
2020 xmlGenericError(xmlGenericErrorContext,
2021 "xmlNodeDump : node == NULL\n");
2027 xmlGenericError(xmlGenericErrorContext,
2028 "xmlNodeDump : buf == NULL\n");
2032 outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2033 if (outbuf == NULL) {
2034 xmlSaveErrMemory("creating buffer");
2037 memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
2038 outbuf->buffer = buf;
2039 outbuf->encoder = NULL;
2040 outbuf->writecallback = NULL;
2041 outbuf->closecallback = NULL;
2042 outbuf->context = NULL;
2043 outbuf->written = 0;
2046 xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
2048 ret = buf->use - use;
2054 * @f: the FILE * for the output
2055 * @doc: the document
2056 * @cur: the current node
2058 * Dump an XML/HTML node, recursive behaviour, children are printed too.
2061 xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
2063 xmlOutputBufferPtr outbuf;
2069 xmlGenericError(xmlGenericErrorContext,
2070 "xmlElemDump : cur == NULL\n");
2076 xmlGenericError(xmlGenericErrorContext,
2077 "xmlElemDump : doc == NULL\n");
2081 outbuf = xmlOutputBufferCreateFile(f, NULL);
2084 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
2085 #ifdef LIBXML_HTML_ENABLED
2086 htmlNodeDumpOutput(outbuf, doc, cur, NULL);
2088 xmlSaveErr(XML_ERR_INTERNAL_ERROR, cur, "HTML support not compiled in\n");
2089 #endif /* LIBXML_HTML_ENABLED */
2091 xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
2092 xmlOutputBufferClose(outbuf);
2095 /************************************************************************
2097 * Saving functions front-ends *
2099 ************************************************************************/
2102 * xmlNodeDumpOutput:
2103 * @buf: the XML buffer output
2104 * @doc: the document
2105 * @cur: the current node
2106 * @level: the imbrication level for indenting
2107 * @format: is formatting allowed
2108 * @encoding: an optional encoding string
2110 * Dump an XML node, recursive behaviour, children are printed too.
2111 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
2112 * or xmlKeepBlanksDefault(0) was called
2115 xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
2116 int level, int format, const char *encoding)
2119 #ifdef LIBXML_HTML_ENABLED
2126 if ((buf == NULL) || (cur == NULL)) return;
2128 if (encoding == NULL)
2131 memset(&ctxt, 0, sizeof(ctxt));
2135 ctxt.format = format;
2136 ctxt.encoding = (const xmlChar *) encoding;
2137 xmlSaveCtxtInit(&ctxt);
2138 ctxt.options |= XML_SAVE_AS_XML;
2140 #ifdef LIBXML_HTML_ENABLED
2141 dtd = xmlGetIntSubset(doc);
2143 is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
2149 xhtmlNodeDumpOutput(&ctxt, cur);
2152 xmlNodeDumpOutputInternal(&ctxt, cur);
2156 * xmlDocDumpFormatMemoryEnc:
2157 * @out_doc: Document to generate XML text from
2158 * @doc_txt_ptr: Memory pointer for allocated XML text
2159 * @doc_txt_len: Length of the generated XML text
2160 * @txt_encoding: Character encoding to use when generating XML text
2161 * @format: should formatting spaces been added
2163 * Dump the current DOM tree into memory using the character encoding specified
2164 * by the caller. Note it is up to the caller of this function to free the
2165 * allocated memory with xmlFree().
2166 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
2167 * or xmlKeepBlanksDefault(0) was called
2171 xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
2172 int * doc_txt_len, const char * txt_encoding,
2176 xmlOutputBufferPtr out_buff = NULL;
2177 xmlCharEncodingHandlerPtr conv_hdlr = NULL;
2179 if (doc_txt_len == NULL) {
2180 doc_txt_len = &dummy; /* Continue, caller just won't get length */
2183 if (doc_txt_ptr == NULL) {
2188 *doc_txt_ptr = NULL;
2191 if (out_doc == NULL) {
2192 /* No document, no output */
2197 * Validate the encoding value, if provided.
2198 * This logic is copied from xmlSaveFileEnc.
2201 if (txt_encoding == NULL)
2202 txt_encoding = (const char *) out_doc->encoding;
2203 if (txt_encoding != NULL) {
2204 conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
2205 if ( conv_hdlr == NULL ) {
2206 xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, (xmlNodePtr) out_doc,
2212 if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
2213 xmlSaveErrMemory("creating buffer");
2217 memset(&ctxt, 0, sizeof(ctxt));
2219 ctxt.buf = out_buff;
2221 ctxt.format = format;
2222 ctxt.encoding = (const xmlChar *) txt_encoding;
2223 xmlSaveCtxtInit(&ctxt);
2224 ctxt.options |= XML_SAVE_AS_XML;
2225 xmlDocContentDumpOutput(&ctxt, out_doc);
2226 xmlOutputBufferFlush(out_buff);
2227 if (out_buff->conv != NULL) {
2228 *doc_txt_len = out_buff->conv->use;
2229 *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
2231 *doc_txt_len = out_buff->buffer->use;
2232 *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
2234 (void)xmlOutputBufferClose(out_buff);
2236 if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
2238 xmlSaveErrMemory("creating output");
2246 * @cur: the document
2247 * @mem: OUT: the memory pointer
2248 * @size: OUT: the memory length
2250 * Dump an XML document in memory and return the #xmlChar * and it's size
2251 * in bytes. It's up to the caller to free the memory with xmlFree().
2252 * The resulting byte array is zero terminated, though the last 0 is not
2253 * included in the returned size.
2256 xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
2257 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
2261 * xmlDocDumpFormatMemory:
2262 * @cur: the document
2263 * @mem: OUT: the memory pointer
2264 * @size: OUT: the memory length
2265 * @format: should formatting spaces been added
2268 * Dump an XML document in memory and return the #xmlChar * and it's size.
2269 * It's up to the caller to free the memory with xmlFree().
2270 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
2271 * or xmlKeepBlanksDefault(0) was called
2274 xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
2275 xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
2279 * xmlDocDumpMemoryEnc:
2280 * @out_doc: Document to generate XML text from
2281 * @doc_txt_ptr: Memory pointer for allocated XML text
2282 * @doc_txt_len: Length of the generated XML text
2283 * @txt_encoding: Character encoding to use when generating XML text
2285 * Dump the current DOM tree into memory using the character encoding specified
2286 * by the caller. Note it is up to the caller of this function to free the
2287 * allocated memory with xmlFree().
2291 xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
2292 int * doc_txt_len, const char * txt_encoding) {
2293 xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
2300 * @cur: the document
2301 * @format: should formatting spaces been added
2303 * Dump an XML document to an open FILE.
2305 * returns: the number of bytes written or -1 in case of failure.
2306 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
2307 * or xmlKeepBlanksDefault(0) was called
2310 xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
2312 xmlOutputBufferPtr buf;
2313 const char * encoding;
2314 xmlCharEncodingHandlerPtr handler = NULL;
2319 xmlGenericError(xmlGenericErrorContext,
2320 "xmlDocDump : document == NULL\n");
2324 encoding = (const char *) cur->encoding;
2326 if (encoding != NULL) {
2327 handler = xmlFindCharEncodingHandler(encoding);
2328 if (handler == NULL) {
2329 xmlFree((char *) cur->encoding);
2330 cur->encoding = NULL;
2334 buf = xmlOutputBufferCreateFile(f, handler);
2335 if (buf == NULL) return(-1);
2336 memset(&ctxt, 0, sizeof(ctxt));
2340 ctxt.format = format;
2341 ctxt.encoding = (const xmlChar *) encoding;
2342 xmlSaveCtxtInit(&ctxt);
2343 ctxt.options |= XML_SAVE_AS_XML;
2344 xmlDocContentDumpOutput(&ctxt, cur);
2346 ret = xmlOutputBufferClose(buf);
2353 * @cur: the document
2355 * Dump an XML document to an open FILE.
2357 * returns: the number of bytes written or -1 in case of failure.
2360 xmlDocDump(FILE *f, xmlDocPtr cur) {
2361 return(xmlDocFormatDump (f, cur, 0));
2366 * @buf: an output I/O buffer
2367 * @cur: the document
2368 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
2370 * Dump an XML document to an I/O buffer.
2371 * Warning ! This call xmlOutputBufferClose() on buf which is not available
2374 * returns: the number of bytes written or -1 in case of failure.
2377 xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
2381 if (buf == NULL) return(-1);
2383 xmlOutputBufferClose(buf);
2386 memset(&ctxt, 0, sizeof(ctxt));
2391 ctxt.encoding = (const xmlChar *) encoding;
2392 xmlSaveCtxtInit(&ctxt);
2393 ctxt.options |= XML_SAVE_AS_XML;
2394 xmlDocContentDumpOutput(&ctxt, cur);
2395 ret = xmlOutputBufferClose(buf);
2400 * xmlSaveFormatFileTo:
2401 * @buf: an output I/O buffer
2402 * @cur: the document
2403 * @encoding: the encoding if any assuming the I/O layer handles the trancoding
2404 * @format: should formatting spaces been added
2406 * Dump an XML document to an I/O buffer.
2407 * Warning ! This call xmlOutputBufferClose() on buf which is not available
2410 * returns: the number of bytes written or -1 in case of failure.
2413 xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur,
2414 const char *encoding, int format)
2419 if (buf == NULL) return(-1);
2420 if ((cur == NULL) ||
2421 ((cur->type != XML_DOCUMENT_NODE) &&
2422 (cur->type != XML_HTML_DOCUMENT_NODE))) {
2423 xmlOutputBufferClose(buf);
2426 memset(&ctxt, 0, sizeof(ctxt));
2430 ctxt.format = format;
2431 ctxt.encoding = (const xmlChar *) encoding;
2432 xmlSaveCtxtInit(&ctxt);
2433 ctxt.options |= XML_SAVE_AS_XML;
2434 xmlDocContentDumpOutput(&ctxt, cur);
2435 ret = xmlOutputBufferClose(buf);
2440 * xmlSaveFormatFileEnc:
2441 * @filename: the filename or URL to output
2442 * @cur: the document being saved
2443 * @encoding: the name of the encoding to use or NULL.
2444 * @format: should formatting spaces be added.
2446 * Dump an XML document to a file or an URL.
2448 * Returns the number of bytes written or -1 in case of error.
2449 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
2450 * or xmlKeepBlanksDefault(0) was called
2453 xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
2454 const char * encoding, int format ) {
2456 xmlOutputBufferPtr buf;
2457 xmlCharEncodingHandlerPtr handler = NULL;
2463 if (encoding == NULL)
2464 encoding = (const char *) cur->encoding;
2466 if (encoding != NULL) {
2468 handler = xmlFindCharEncodingHandler(encoding);
2469 if (handler == NULL)
2474 if (cur->compression < 0) cur->compression = xmlGetCompressMode();
2477 * save the content to a temp buffer.
2479 buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
2480 if (buf == NULL) return(-1);
2481 memset(&ctxt, 0, sizeof(ctxt));
2485 ctxt.format = format;
2486 ctxt.encoding = (const xmlChar *) encoding;
2487 xmlSaveCtxtInit(&ctxt);
2488 ctxt.options |= XML_SAVE_AS_XML;
2490 xmlDocContentDumpOutput(&ctxt, cur);
2492 ret = xmlOutputBufferClose(buf);
2499 * @filename: the filename (or URL)
2500 * @cur: the document
2501 * @encoding: the name of an encoding (or NULL)
2503 * Dump an XML document, converting it to the given encoding
2505 * returns: the number of bytes written or -1 in case of failure.
2508 xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
2509 return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
2513 * xmlSaveFormatFile:
2514 * @filename: the filename (or URL)
2515 * @cur: the document
2516 * @format: should formatting spaces been added
2518 * Dump an XML document to a file. Will use compression if
2519 * compiled in and enabled. If @filename is "-" the stdout file is
2520 * used. If @format is set then the document will be indented on output.
2521 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
2522 * or xmlKeepBlanksDefault(0) was called
2524 * returns: the number of bytes written or -1 in case of failure.
2527 xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
2528 return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
2533 * @filename: the filename (or URL)
2534 * @cur: the document
2536 * Dump an XML document to a file. Will use compression if
2537 * compiled in and enabled. If @filename is "-" the stdout file is
2539 * returns: the number of bytes written or -1 in case of failure.
2542 xmlSaveFile(const char *filename, xmlDocPtr cur) {
2543 return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
2546 #endif /* LIBXML_OUTPUT_ENABLED */
2548 #define bottom_xmlsave
2549 #include "elfgcchack.h"