2 * xmlsave.c: Implementation 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 #include "private/buf.h"
23 #include "private/enc.h"
24 #include "private/error.h"
25 #include "private/save.h"
27 #ifdef LIBXML_OUTPUT_ENABLED
29 #define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
32 xmlGenericError(xmlGenericErrorContext, \
33 "Unimplemented block at %s:%d\n", \
40 const xmlChar
*filename
;
41 const xmlChar
*encoding
;
42 xmlCharEncodingHandlerPtr handler
;
43 xmlOutputBufferPtr buf
;
47 char indent
[MAX_INDENT
+ 1]; /* array for indenting output */
50 xmlCharEncodingOutputFunc escape
; /* used for element content */
51 xmlCharEncodingOutputFunc escapeAttr
;/* used for attribute content */
54 /************************************************************************
56 * Output error handlers *
58 ************************************************************************/
61 * @extra: extra information
63 * Handle an out of memory condition
66 xmlSaveErrMemory(const char *extra
)
68 __xmlSimpleError(XML_FROM_OUTPUT
, XML_ERR_NO_MEMORY
, NULL
, NULL
, extra
);
73 * @code: the error number
74 * @node: the location of the error.
75 * @extra: extra information
77 * Handle an out of memory condition
80 xmlSaveErr(int code
, xmlNodePtr node
, const char *extra
)
82 const char *msg
= NULL
;
85 case XML_SAVE_NOT_UTF8
:
86 msg
= "string is not in UTF-8\n";
88 case XML_SAVE_CHAR_INVALID
:
89 msg
= "invalid character value\n";
91 case XML_SAVE_UNKNOWN_ENCODING
:
92 msg
= "unknown encoding %s\n";
94 case XML_SAVE_NO_DOCTYPE
:
95 msg
= "document has no DOCTYPE\n";
98 msg
= "unexpected error number\n";
100 __xmlSimpleError(XML_FROM_OUTPUT
, code
, node
, msg
, extra
);
103 /************************************************************************
105 * Special escaping routines *
107 ************************************************************************/
108 static unsigned char *
109 xmlSerializeHexCharRef(unsigned char *out
, int val
) {
115 if (val
< 0x10) ptr
= out
;
116 else if (val
< 0x100) ptr
= out
+ 1;
117 else if (val
< 0x1000) ptr
= out
+ 2;
118 else if (val
< 0x10000) ptr
= out
+ 3;
119 else if (val
< 0x100000) ptr
= out
+ 4;
124 case 0: *ptr
-- = '0'; break;
125 case 1: *ptr
-- = '1'; break;
126 case 2: *ptr
-- = '2'; break;
127 case 3: *ptr
-- = '3'; break;
128 case 4: *ptr
-- = '4'; break;
129 case 5: *ptr
-- = '5'; break;
130 case 6: *ptr
-- = '6'; break;
131 case 7: *ptr
-- = '7'; break;
132 case 8: *ptr
-- = '8'; break;
133 case 9: *ptr
-- = '9'; break;
134 case 0xA: *ptr
-- = 'A'; break;
135 case 0xB: *ptr
-- = 'B'; break;
136 case 0xC: *ptr
-- = 'C'; break;
137 case 0xD: *ptr
-- = 'D'; break;
138 case 0xE: *ptr
-- = 'E'; break;
139 case 0xF: *ptr
-- = 'F'; break;
140 default: *ptr
-- = '0'; break;
151 * @out: a pointer to an array of bytes to store the result
152 * @outlen: the length of @out
153 * @in: a pointer to an array of unescaped UTF-8 bytes
154 * @inlen: the length of @in
156 * Take a block of UTF-8 chars in and escape them. Used when there is no
157 * encoding specified.
159 * Returns 0 if success, or -1 otherwise
160 * The value of @inlen after return is the number of octets consumed
161 * if the return value is positive, else unpredictable.
162 * The value of @outlen after return is the number of octets consumed.
165 xmlEscapeEntities(unsigned char* out
, int *outlen
,
166 const xmlChar
* in
, int *inlen
) {
167 unsigned char* outstart
= out
;
168 const unsigned char* base
= in
;
169 unsigned char* outend
= out
+ *outlen
;
170 const unsigned char* inend
;
173 inend
= in
+ (*inlen
);
175 while ((in
< inend
) && (out
< outend
)) {
177 if (outend
- out
< 4) break;
184 } else if (*in
== '>') {
185 if (outend
- out
< 4) break;
192 } else if (*in
== '&') {
193 if (outend
- out
< 5) break;
201 } else if (((*in
>= 0x20) && (*in
< 0x80)) ||
202 (*in
== '\n') || (*in
== '\t')) {
204 * default case, just copy !
208 } else if (*in
>= 0x80) {
210 * We assume we have UTF-8 input.
212 if (outend
- out
< 11) break;
215 xmlSaveErr(XML_SAVE_NOT_UTF8
, NULL
, NULL
);
218 } else if (*in
< 0xE0) {
219 if (inend
- in
< 2) break;
220 val
= (in
[0]) & 0x1F;
222 val
|= (in
[1]) & 0x3F;
224 } else if (*in
< 0xF0) {
225 if (inend
- in
< 3) break;
226 val
= (in
[0]) & 0x0F;
228 val
|= (in
[1]) & 0x3F;
230 val
|= (in
[2]) & 0x3F;
232 } else if (*in
< 0xF8) {
233 if (inend
- in
< 4) break;
234 val
= (in
[0]) & 0x07;
236 val
|= (in
[1]) & 0x3F;
238 val
|= (in
[2]) & 0x3F;
240 val
|= (in
[3]) & 0x3F;
243 xmlSaveErr(XML_SAVE_CHAR_INVALID
, NULL
, NULL
);
248 xmlSaveErr(XML_SAVE_CHAR_INVALID
, NULL
, NULL
);
254 * We could do multiple things here. Just save as a char ref
256 out
= xmlSerializeHexCharRef(out
, val
);
257 } else if (IS_BYTE_CHAR(*in
)) {
258 if (outend
- out
< 6) break;
259 out
= xmlSerializeHexCharRef(out
, *in
++);
261 xmlGenericError(xmlGenericErrorContext
,
262 "xmlEscapeEntities : char out of range\n");
267 *outlen
= out
- outstart
;
271 *outlen
= out
- outstart
;
276 /************************************************************************
278 * Allocation and deallocation *
280 ************************************************************************/
283 * @ctxt: the saving context
285 * Initialize a saving context
288 xmlSaveCtxtInit(xmlSaveCtxtPtr ctxt
)
293 if (ctxt
== NULL
) return;
294 if ((ctxt
->encoding
== NULL
) && (ctxt
->escape
== NULL
))
295 ctxt
->escape
= xmlEscapeEntities
;
296 len
= xmlStrlen((xmlChar
*)xmlTreeIndentString
);
297 if ((xmlTreeIndentString
== NULL
) || (len
== 0)) {
298 memset(&ctxt
->indent
[0], 0, MAX_INDENT
+ 1);
300 ctxt
->indent_size
= len
;
301 ctxt
->indent_nr
= MAX_INDENT
/ ctxt
->indent_size
;
302 for (i
= 0;i
< ctxt
->indent_nr
;i
++)
303 memcpy(&ctxt
->indent
[i
* ctxt
->indent_size
], xmlTreeIndentString
,
305 ctxt
->indent
[ctxt
->indent_nr
* ctxt
->indent_size
] = 0;
308 if (xmlSaveNoEmptyTags
) {
309 ctxt
->options
|= XML_SAVE_NO_EMPTY
;
316 * Free a saving context, destroying the output in any remaining buffer
319 xmlFreeSaveCtxt(xmlSaveCtxtPtr ctxt
)
321 if (ctxt
== NULL
) return;
322 if (ctxt
->encoding
!= NULL
)
323 xmlFree((char *) ctxt
->encoding
);
324 if (ctxt
->buf
!= NULL
)
325 xmlOutputBufferClose(ctxt
->buf
);
332 * Create a new saving context
334 * Returns the new structure or NULL in case of error
336 static xmlSaveCtxtPtr
337 xmlNewSaveCtxt(const char *encoding
, int options
)
341 ret
= (xmlSaveCtxtPtr
) xmlMalloc(sizeof(xmlSaveCtxt
));
343 xmlSaveErrMemory("creating saving context");
346 memset(ret
, 0, sizeof(xmlSaveCtxt
));
348 if (encoding
!= NULL
) {
349 ret
->handler
= xmlFindCharEncodingHandler(encoding
);
350 if (ret
->handler
== NULL
) {
351 xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING
, NULL
, encoding
);
352 xmlFreeSaveCtxt(ret
);
355 ret
->encoding
= xmlStrdup((const xmlChar
*)encoding
);
358 xmlSaveCtxtInit(ret
);
364 /* Re-check this option as it may already have been set */
365 if ((ret
->options
& XML_SAVE_NO_EMPTY
) && ! (options
& XML_SAVE_NO_EMPTY
)) {
366 options
|= XML_SAVE_NO_EMPTY
;
369 ret
->options
= options
;
370 if (options
& XML_SAVE_FORMAT
)
372 else if (options
& XML_SAVE_WSNONSIG
)
378 /************************************************************************
380 * Dumping XML tree content to a simple buffer *
382 ************************************************************************/
384 * xmlAttrSerializeContent:
385 * @buf: the XML buffer output
387 * @attr: the attribute pointer
389 * Serialize the attribute in the buffer
392 xmlAttrSerializeContent(xmlOutputBufferPtr buf
, xmlAttrPtr attr
)
396 children
= attr
->children
;
397 while (children
!= NULL
) {
398 switch (children
->type
) {
400 xmlBufAttrSerializeTxtContent(buf
->buffer
, attr
->doc
,
401 attr
, children
->content
);
403 case XML_ENTITY_REF_NODE
:
404 xmlBufAdd(buf
->buffer
, BAD_CAST
"&", 1);
405 xmlBufAdd(buf
->buffer
, children
->name
,
406 xmlStrlen(children
->name
));
407 xmlBufAdd(buf
->buffer
, BAD_CAST
";", 1);
410 /* should not happen unless we have a badly built tree */
413 children
= children
->next
;
418 * xmlBufDumpNotationTable:
419 * @buf: an xmlBufPtr output
420 * @table: A notation table
422 * This will dump the content of the notation table as an XML DTD definition
425 xmlBufDumpNotationTable(xmlBufPtr buf
, xmlNotationTablePtr table
) {
428 buffer
= xmlBufferCreate();
429 if (buffer
== NULL
) {
431 * TODO set the error in buf
435 xmlBufferSetAllocationScheme(buffer
, XML_BUFFER_ALLOC_DOUBLEIT
);
436 xmlDumpNotationTable(buffer
, table
);
437 xmlBufMergeBuffer(buf
, buffer
);
441 * xmlBufDumpElementDecl:
442 * @buf: an xmlBufPtr output
443 * @elem: An element table
445 * This will dump the content of the element declaration as an XML
449 xmlBufDumpElementDecl(xmlBufPtr buf
, xmlElementPtr elem
) {
452 buffer
= xmlBufferCreate();
453 if (buffer
== NULL
) {
455 * TODO set the error in buf
459 xmlBufferSetAllocationScheme(buffer
, XML_BUFFER_ALLOC_DOUBLEIT
);
460 xmlDumpElementDecl(buffer
, elem
);
461 xmlBufMergeBuffer(buf
, buffer
);
465 * xmlBufDumpAttributeDecl:
466 * @buf: an xmlBufPtr output
467 * @attr: An attribute declaration
469 * This will dump the content of the attribute declaration as an XML
473 xmlBufDumpAttributeDecl(xmlBufPtr buf
, xmlAttributePtr attr
) {
476 buffer
= xmlBufferCreate();
477 if (buffer
== NULL
) {
479 * TODO set the error in buf
483 xmlBufferSetAllocationScheme(buffer
, XML_BUFFER_ALLOC_DOUBLEIT
);
484 xmlDumpAttributeDecl(buffer
, attr
);
485 xmlBufMergeBuffer(buf
, buffer
);
489 * xmlBufDumpEntityDecl:
490 * @buf: an xmlBufPtr output
491 * @ent: An entity table
493 * This will dump the content of the entity table as an XML DTD definition
496 xmlBufDumpEntityDecl(xmlBufPtr buf
, xmlEntityPtr ent
) {
499 buffer
= xmlBufferCreate();
500 if (buffer
== NULL
) {
502 * TODO set the error in buf
506 xmlBufferSetAllocationScheme(buffer
, XML_BUFFER_ALLOC_DOUBLEIT
);
507 xmlDumpEntityDecl(buffer
, ent
);
508 xmlBufMergeBuffer(buf
, buffer
);
511 /************************************************************************
513 * Dumping XML tree content to an I/O output buffer *
515 ************************************************************************/
517 static int xmlSaveSwitchEncoding(xmlSaveCtxtPtr ctxt
, const char *encoding
) {
518 xmlOutputBufferPtr buf
= ctxt
->buf
;
520 if ((encoding
!= NULL
) && (buf
->encoder
== NULL
) && (buf
->conv
== NULL
)) {
521 buf
->encoder
= xmlFindCharEncodingHandler((const char *)encoding
);
522 if (buf
->encoder
== NULL
) {
523 xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING
, NULL
,
524 (const char *)encoding
);
527 buf
->conv
= xmlBufCreate();
528 if (buf
->conv
== NULL
) {
529 xmlCharEncCloseFunc(buf
->encoder
);
530 xmlSaveErrMemory("creating encoding buffer");
534 * initialize the state, e.g. if outputting a BOM
536 xmlCharEncOutput(buf
, 1);
541 static int xmlSaveClearEncoding(xmlSaveCtxtPtr ctxt
) {
542 xmlOutputBufferPtr buf
= ctxt
->buf
;
543 xmlOutputBufferFlush(buf
);
544 xmlCharEncCloseFunc(buf
->encoder
);
545 xmlBufFree(buf
->conv
);
551 #ifdef LIBXML_HTML_ENABLED
553 xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt
, xmlNodePtr cur
);
555 static void xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt
, xmlNodePtr cur
);
556 static int xmlDocContentDumpOutput(xmlSaveCtxtPtr ctxt
, xmlDocPtr cur
);
559 * xmlOutputBufferWriteWSNonSig:
560 * @ctxt: The save context
561 * @extra: Number of extra indents to apply to ctxt->level
563 * Write out formatting for non-significant whitespace output.
566 xmlOutputBufferWriteWSNonSig(xmlSaveCtxtPtr ctxt
, int extra
)
569 if ((ctxt
== NULL
) || (ctxt
->buf
== NULL
))
571 xmlOutputBufferWrite(ctxt
->buf
, 1, "\n");
572 for (i
= 0; i
< (ctxt
->level
+ extra
); i
+= ctxt
->indent_nr
) {
573 xmlOutputBufferWrite(ctxt
->buf
, ctxt
->indent_size
*
574 ((ctxt
->level
+ extra
- i
) > ctxt
->indent_nr
?
575 ctxt
->indent_nr
: (ctxt
->level
+ extra
- i
)),
582 * @buf: the XML buffer output
584 * @ctxt: the output save context. Optional.
586 * Dump a local Namespace definition.
587 * Should be called in the context of attributes dumps.
588 * If @ctxt is supplied, @buf should be its buffer.
591 xmlNsDumpOutput(xmlOutputBufferPtr buf
, xmlNsPtr cur
, xmlSaveCtxtPtr ctxt
) {
592 if ((cur
== NULL
) || (buf
== NULL
)) return;
593 if ((cur
->type
== XML_LOCAL_NAMESPACE
) && (cur
->href
!= NULL
)) {
594 if (xmlStrEqual(cur
->prefix
, BAD_CAST
"xml"))
597 if (ctxt
!= NULL
&& ctxt
->format
== 2)
598 xmlOutputBufferWriteWSNonSig(ctxt
, 2);
600 xmlOutputBufferWrite(buf
, 1, " ");
602 /* Within the context of an element attributes */
603 if (cur
->prefix
!= NULL
) {
604 xmlOutputBufferWrite(buf
, 6, "xmlns:");
605 xmlOutputBufferWriteString(buf
, (const char *)cur
->prefix
);
607 xmlOutputBufferWrite(buf
, 5, "xmlns");
608 xmlOutputBufferWrite(buf
, 1, "=");
609 xmlBufWriteQuotedString(buf
->buffer
, cur
->href
);
614 * xmlNsDumpOutputCtxt
615 * @ctxt: the save context
618 * Dump a local Namespace definition to a save context.
619 * Should be called in the context of attribute dumps.
622 xmlNsDumpOutputCtxt(xmlSaveCtxtPtr ctxt
, xmlNsPtr cur
) {
623 xmlNsDumpOutput(ctxt
->buf
, cur
, ctxt
);
627 * xmlNsListDumpOutputCtxt
628 * @ctxt: the save context
629 * @cur: the first namespace
631 * Dump a list of local namespace definitions to a save context.
632 * Should be called in the context of attribute dumps.
635 xmlNsListDumpOutputCtxt(xmlSaveCtxtPtr ctxt
, xmlNsPtr cur
) {
636 while (cur
!= NULL
) {
637 xmlNsDumpOutput(ctxt
->buf
, cur
, ctxt
);
643 * xmlNsListDumpOutput:
644 * @buf: the XML buffer output
645 * @cur: the first namespace
647 * Dump a list of local Namespace definitions.
648 * Should be called in the context of attributes dumps.
651 xmlNsListDumpOutput(xmlOutputBufferPtr buf
, xmlNsPtr cur
) {
652 while (cur
!= NULL
) {
653 xmlNsDumpOutput(buf
, cur
, NULL
);
660 * @buf: the XML buffer output
661 * @dtd: the pointer to the DTD
663 * Dump the XML document DTD, if any.
666 xmlDtdDumpOutput(xmlSaveCtxtPtr ctxt
, xmlDtdPtr dtd
) {
667 xmlOutputBufferPtr buf
;
671 if (dtd
== NULL
) return;
672 if ((ctxt
== NULL
) || (ctxt
->buf
== NULL
))
675 xmlOutputBufferWrite(buf
, 10, "<!DOCTYPE ");
676 xmlOutputBufferWriteString(buf
, (const char *)dtd
->name
);
677 if (dtd
->ExternalID
!= NULL
) {
678 xmlOutputBufferWrite(buf
, 8, " PUBLIC ");
679 xmlBufWriteQuotedString(buf
->buffer
, dtd
->ExternalID
);
680 xmlOutputBufferWrite(buf
, 1, " ");
681 xmlBufWriteQuotedString(buf
->buffer
, dtd
->SystemID
);
682 } else if (dtd
->SystemID
!= NULL
) {
683 xmlOutputBufferWrite(buf
, 8, " SYSTEM ");
684 xmlBufWriteQuotedString(buf
->buffer
, dtd
->SystemID
);
686 if ((dtd
->entities
== NULL
) && (dtd
->elements
== NULL
) &&
687 (dtd
->attributes
== NULL
) && (dtd
->notations
== NULL
) &&
688 (dtd
->pentities
== NULL
)) {
689 xmlOutputBufferWrite(buf
, 1, ">");
692 xmlOutputBufferWrite(buf
, 3, " [\n");
694 * Dump the notations first they are not in the DTD children list
695 * Do this only on a standalone DTD or on the internal subset though.
697 if ((dtd
->notations
!= NULL
) && ((dtd
->doc
== NULL
) ||
698 (dtd
->doc
->intSubset
== dtd
))) {
699 xmlBufDumpNotationTable(buf
->buffer
,
700 (xmlNotationTablePtr
) dtd
->notations
);
702 format
= ctxt
->format
;
706 for (cur
= dtd
->children
; cur
!= NULL
; cur
= cur
->next
) {
707 xmlNodeDumpOutputInternal(ctxt
, cur
);
709 ctxt
->format
= format
;
711 xmlOutputBufferWrite(buf
, 2, "]>");
716 * @buf: the XML buffer output
717 * @cur: the attribute pointer
719 * Dump an XML attribute
722 xmlAttrDumpOutput(xmlSaveCtxtPtr ctxt
, xmlAttrPtr cur
) {
723 xmlOutputBufferPtr buf
;
725 if (cur
== NULL
) return;
727 if (buf
== NULL
) return;
728 if (ctxt
->format
== 2)
729 xmlOutputBufferWriteWSNonSig(ctxt
, 2);
731 xmlOutputBufferWrite(buf
, 1, " ");
732 if ((cur
->ns
!= NULL
) && (cur
->ns
->prefix
!= NULL
)) {
733 xmlOutputBufferWriteString(buf
, (const char *)cur
->ns
->prefix
);
734 xmlOutputBufferWrite(buf
, 1, ":");
736 xmlOutputBufferWriteString(buf
, (const char *)cur
->name
);
737 xmlOutputBufferWrite(buf
, 2, "=\"");
738 xmlAttrSerializeContent(buf
, cur
);
739 xmlOutputBufferWrite(buf
, 1, "\"");
742 #ifdef LIBXML_HTML_ENABLED
744 * htmlNodeDumpOutputInternal:
745 * @cur: the current node
747 * Dump an HTML node, recursive behaviour, children are printed too.
750 htmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt
, xmlNodePtr cur
) {
751 const xmlChar
*oldenc
= NULL
;
752 const xmlChar
*oldctxtenc
= ctxt
->encoding
;
753 const xmlChar
*encoding
= ctxt
->encoding
;
754 xmlOutputBufferPtr buf
= ctxt
->buf
;
755 int switched_encoding
= 0;
762 oldenc
= doc
->encoding
;
763 if (ctxt
->encoding
!= NULL
) {
764 doc
->encoding
= BAD_CAST ctxt
->encoding
;
765 } else if (doc
->encoding
!= NULL
) {
766 encoding
= doc
->encoding
;
770 if ((encoding
!= NULL
) && (doc
!= NULL
))
771 htmlSetMetaEncoding(doc
, (const xmlChar
*) encoding
);
772 if ((encoding
== NULL
) && (doc
!= NULL
))
773 encoding
= htmlGetMetaEncoding(doc
);
774 if (encoding
== NULL
)
775 encoding
= BAD_CAST
"HTML";
776 if ((encoding
!= NULL
) && (oldctxtenc
== NULL
) &&
777 (buf
->encoder
== NULL
) && (buf
->conv
== NULL
)) {
778 if (xmlSaveSwitchEncoding(ctxt
, (const char*) encoding
) < 0) {
779 doc
->encoding
= oldenc
;
782 switched_encoding
= 1;
784 if (ctxt
->options
& XML_SAVE_FORMAT
)
785 htmlNodeDumpFormatOutput(buf
, doc
, cur
,
786 (const char *)encoding
, 1);
788 htmlNodeDumpFormatOutput(buf
, doc
, cur
,
789 (const char *)encoding
, 0);
791 * Restore the state of the saving context at the end of the document
793 if ((switched_encoding
) && (oldctxtenc
== NULL
)) {
794 xmlSaveClearEncoding(ctxt
);
797 doc
->encoding
= oldenc
;
803 * xmlNodeDumpOutputInternal:
804 * @cur: the current node
806 * Dump an XML node, recursive behaviour, children are printed too.
809 xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt
, xmlNodePtr cur
) {
810 int format
= ctxt
->format
;
811 xmlNodePtr tmp
, root
, unformattedNode
= NULL
, parent
;
813 xmlChar
*start
, *end
;
814 xmlOutputBufferPtr buf
;
816 if (cur
== NULL
) return;
820 parent
= cur
->parent
;
823 case XML_DOCUMENT_NODE
:
824 case XML_HTML_DOCUMENT_NODE
:
825 xmlDocContentDumpOutput(ctxt
, (xmlDocPtr
) cur
);
829 xmlDtdDumpOutput(ctxt
, (xmlDtdPtr
) cur
);
832 case XML_DOCUMENT_FRAG_NODE
:
833 /* Always validate cur->parent when descending. */
834 if ((cur
->parent
== parent
) && (cur
->children
!= NULL
)) {
841 case XML_ELEMENT_DECL
:
842 xmlBufDumpElementDecl(buf
->buffer
, (xmlElementPtr
) cur
);
845 case XML_ATTRIBUTE_DECL
:
846 xmlBufDumpAttributeDecl(buf
->buffer
, (xmlAttributePtr
) cur
);
849 case XML_ENTITY_DECL
:
850 xmlBufDumpEntityDecl(buf
->buffer
, (xmlEntityPtr
) cur
);
853 case XML_ELEMENT_NODE
:
854 if ((cur
!= root
) && (ctxt
->format
== 1) &&
855 (xmlIndentTreeOutput
))
856 xmlOutputBufferWrite(buf
, ctxt
->indent_size
*
857 (ctxt
->level
> ctxt
->indent_nr
?
858 ctxt
->indent_nr
: ctxt
->level
),
862 * Some users like lxml are known to pass nodes with a corrupted
863 * tree structure. Fall back to a recursive call to handle this
866 if ((cur
->parent
!= parent
) && (cur
->children
!= NULL
)) {
867 xmlNodeDumpOutputInternal(ctxt
, cur
);
871 xmlOutputBufferWrite(buf
, 1, "<");
872 if ((cur
->ns
!= NULL
) && (cur
->ns
->prefix
!= NULL
)) {
873 xmlOutputBufferWriteString(buf
, (const char *)cur
->ns
->prefix
);
874 xmlOutputBufferWrite(buf
, 1, ":");
876 xmlOutputBufferWriteString(buf
, (const char *)cur
->name
);
878 xmlNsListDumpOutputCtxt(ctxt
, cur
->nsDef
);
879 for (attr
= cur
->properties
; attr
!= NULL
; attr
= attr
->next
)
880 xmlAttrDumpOutput(ctxt
, attr
);
882 if (cur
->children
== NULL
) {
883 if ((ctxt
->options
& XML_SAVE_NO_EMPTY
) == 0) {
884 if (ctxt
->format
== 2)
885 xmlOutputBufferWriteWSNonSig(ctxt
, 0);
886 xmlOutputBufferWrite(buf
, 2, "/>");
888 if (ctxt
->format
== 2)
889 xmlOutputBufferWriteWSNonSig(ctxt
, 1);
890 xmlOutputBufferWrite(buf
, 3, "></");
891 if ((cur
->ns
!= NULL
) && (cur
->ns
->prefix
!= NULL
)) {
892 xmlOutputBufferWriteString(buf
,
893 (const char *)cur
->ns
->prefix
);
894 xmlOutputBufferWrite(buf
, 1, ":");
896 xmlOutputBufferWriteString(buf
, (const char *)cur
->name
);
897 if (ctxt
->format
== 2)
898 xmlOutputBufferWriteWSNonSig(ctxt
, 0);
899 xmlOutputBufferWrite(buf
, 1, ">");
902 if (ctxt
->format
== 1) {
904 while (tmp
!= NULL
) {
905 if ((tmp
->type
== XML_TEXT_NODE
) ||
906 (tmp
->type
== XML_CDATA_SECTION_NODE
) ||
907 (tmp
->type
== XML_ENTITY_REF_NODE
)) {
909 unformattedNode
= cur
;
915 if (ctxt
->format
== 2)
916 xmlOutputBufferWriteWSNonSig(ctxt
, 1);
917 xmlOutputBufferWrite(buf
, 1, ">");
918 if (ctxt
->format
== 1) xmlOutputBufferWrite(buf
, 1, "\n");
919 if (ctxt
->level
>= 0) ctxt
->level
++;
928 if (cur
->content
== NULL
)
930 if (cur
->name
!= xmlStringTextNoenc
) {
931 xmlOutputBufferWriteEscape(buf
, cur
->content
, ctxt
->escape
);
934 * Disable escaping, needed for XSLT
936 xmlOutputBufferWriteString(buf
, (const char *) cur
->content
);
941 if ((cur
!= root
) && (ctxt
->format
== 1) && (xmlIndentTreeOutput
))
942 xmlOutputBufferWrite(buf
, ctxt
->indent_size
*
943 (ctxt
->level
> ctxt
->indent_nr
?
944 ctxt
->indent_nr
: ctxt
->level
),
947 if (cur
->content
!= NULL
) {
948 xmlOutputBufferWrite(buf
, 2, "<?");
949 xmlOutputBufferWriteString(buf
, (const char *)cur
->name
);
950 if (cur
->content
!= NULL
) {
951 if (ctxt
->format
== 2)
952 xmlOutputBufferWriteWSNonSig(ctxt
, 0);
954 xmlOutputBufferWrite(buf
, 1, " ");
955 xmlOutputBufferWriteString(buf
,
956 (const char *)cur
->content
);
958 xmlOutputBufferWrite(buf
, 2, "?>");
960 xmlOutputBufferWrite(buf
, 2, "<?");
961 xmlOutputBufferWriteString(buf
, (const char *)cur
->name
);
962 if (ctxt
->format
== 2)
963 xmlOutputBufferWriteWSNonSig(ctxt
, 0);
964 xmlOutputBufferWrite(buf
, 2, "?>");
968 case XML_COMMENT_NODE
:
969 if ((cur
!= root
) && (ctxt
->format
== 1) && (xmlIndentTreeOutput
))
970 xmlOutputBufferWrite(buf
, ctxt
->indent_size
*
971 (ctxt
->level
> ctxt
->indent_nr
?
972 ctxt
->indent_nr
: ctxt
->level
),
975 if (cur
->content
!= NULL
) {
976 xmlOutputBufferWrite(buf
, 4, "<!--");
977 xmlOutputBufferWriteString(buf
, (const char *)cur
->content
);
978 xmlOutputBufferWrite(buf
, 3, "-->");
982 case XML_ENTITY_REF_NODE
:
983 xmlOutputBufferWrite(buf
, 1, "&");
984 xmlOutputBufferWriteString(buf
, (const char *)cur
->name
);
985 xmlOutputBufferWrite(buf
, 1, ";");
988 case XML_CDATA_SECTION_NODE
:
989 if (cur
->content
== NULL
|| *cur
->content
== '\0') {
990 xmlOutputBufferWrite(buf
, 12, "<![CDATA[]]>");
992 start
= end
= cur
->content
;
993 while (*end
!= '\0') {
994 if ((*end
== ']') && (*(end
+ 1) == ']') &&
995 (*(end
+ 2) == '>')) {
997 xmlOutputBufferWrite(buf
, 9, "<![CDATA[");
998 xmlOutputBufferWrite(buf
, end
- start
,
999 (const char *)start
);
1000 xmlOutputBufferWrite(buf
, 3, "]]>");
1006 xmlOutputBufferWrite(buf
, 9, "<![CDATA[");
1007 xmlOutputBufferWriteString(buf
, (const char *)start
);
1008 xmlOutputBufferWrite(buf
, 3, "]]>");
1013 case XML_ATTRIBUTE_NODE
:
1014 xmlAttrDumpOutput(ctxt
, (xmlAttrPtr
) cur
);
1017 case XML_NAMESPACE_DECL
:
1018 xmlNsDumpOutputCtxt(ctxt
, (xmlNsPtr
) cur
);
1028 if ((ctxt
->format
== 1) &&
1029 (cur
->type
!= XML_XINCLUDE_START
) &&
1030 (cur
->type
!= XML_XINCLUDE_END
))
1031 xmlOutputBufferWrite(buf
, 1, "\n");
1032 if (cur
->next
!= NULL
) {
1038 /* cur->parent was validated when descending. */
1039 parent
= cur
->parent
;
1041 if (cur
->type
== XML_ELEMENT_NODE
) {
1042 if (ctxt
->level
> 0) ctxt
->level
--;
1043 if ((xmlIndentTreeOutput
) && (ctxt
->format
== 1))
1044 xmlOutputBufferWrite(buf
, ctxt
->indent_size
*
1045 (ctxt
->level
> ctxt
->indent_nr
?
1046 ctxt
->indent_nr
: ctxt
->level
),
1049 xmlOutputBufferWrite(buf
, 2, "</");
1050 if ((cur
->ns
!= NULL
) && (cur
->ns
->prefix
!= NULL
)) {
1051 xmlOutputBufferWriteString(buf
,
1052 (const char *)cur
->ns
->prefix
);
1053 xmlOutputBufferWrite(buf
, 1, ":");
1056 xmlOutputBufferWriteString(buf
, (const char *)cur
->name
);
1057 if (ctxt
->format
== 2)
1058 xmlOutputBufferWriteWSNonSig(ctxt
, 0);
1059 xmlOutputBufferWrite(buf
, 1, ">");
1061 if (cur
== unformattedNode
) {
1062 ctxt
->format
= format
;
1063 unformattedNode
= NULL
;
1071 * xmlDocContentDumpOutput:
1072 * @cur: the document
1074 * Dump an XML document.
1077 xmlDocContentDumpOutput(xmlSaveCtxtPtr ctxt
, xmlDocPtr cur
) {
1078 #ifdef LIBXML_HTML_ENABLED
1082 const xmlChar
*oldenc
= cur
->encoding
;
1083 const xmlChar
*oldctxtenc
= ctxt
->encoding
;
1084 const xmlChar
*encoding
= ctxt
->encoding
;
1085 xmlCharEncodingOutputFunc oldescape
= ctxt
->escape
;
1086 xmlCharEncodingOutputFunc oldescapeAttr
= ctxt
->escapeAttr
;
1087 xmlOutputBufferPtr buf
= ctxt
->buf
;
1088 xmlCharEncoding enc
;
1089 int switched_encoding
= 0;
1093 if ((cur
->type
!= XML_HTML_DOCUMENT_NODE
) &&
1094 (cur
->type
!= XML_DOCUMENT_NODE
))
1097 if (ctxt
->encoding
!= NULL
) {
1098 cur
->encoding
= BAD_CAST ctxt
->encoding
;
1099 } else if (cur
->encoding
!= NULL
) {
1100 encoding
= cur
->encoding
;
1103 if (((cur
->type
== XML_HTML_DOCUMENT_NODE
) &&
1104 ((ctxt
->options
& XML_SAVE_AS_XML
) == 0) &&
1105 ((ctxt
->options
& XML_SAVE_XHTML
) == 0)) ||
1106 (ctxt
->options
& XML_SAVE_AS_HTML
)) {
1107 #ifdef LIBXML_HTML_ENABLED
1108 if (encoding
!= NULL
)
1109 htmlSetMetaEncoding(cur
, (const xmlChar
*) encoding
);
1110 if (encoding
== NULL
)
1111 encoding
= htmlGetMetaEncoding(cur
);
1112 if (encoding
== NULL
)
1113 encoding
= BAD_CAST
"HTML";
1114 if ((encoding
!= NULL
) && (oldctxtenc
== NULL
) &&
1115 (buf
->encoder
== NULL
) && (buf
->conv
== NULL
)) {
1116 if (xmlSaveSwitchEncoding(ctxt
, (const char*) encoding
) < 0) {
1117 cur
->encoding
= oldenc
;
1121 if (ctxt
->options
& XML_SAVE_FORMAT
)
1122 htmlDocContentDumpFormatOutput(buf
, cur
,
1123 (const char *)encoding
, 1);
1125 htmlDocContentDumpFormatOutput(buf
, cur
,
1126 (const char *)encoding
, 0);
1127 if (ctxt
->encoding
!= NULL
)
1128 cur
->encoding
= oldenc
;
1133 } else if ((cur
->type
== XML_DOCUMENT_NODE
) ||
1134 (ctxt
->options
& XML_SAVE_AS_XML
) ||
1135 (ctxt
->options
& XML_SAVE_XHTML
)) {
1136 enc
= xmlParseCharEncoding((const char*) encoding
);
1137 if ((encoding
!= NULL
) && (oldctxtenc
== NULL
) &&
1138 (buf
->encoder
== NULL
) && (buf
->conv
== NULL
) &&
1139 ((ctxt
->options
& XML_SAVE_NO_DECL
) == 0)) {
1140 if ((enc
!= XML_CHAR_ENCODING_UTF8
) &&
1141 (enc
!= XML_CHAR_ENCODING_NONE
) &&
1142 (enc
!= XML_CHAR_ENCODING_ASCII
)) {
1144 * we need to switch to this encoding but just for this
1145 * document since we output the XMLDecl the conversion
1146 * must be done to not generate not well formed documents.
1148 if (xmlSaveSwitchEncoding(ctxt
, (const char*) encoding
) < 0) {
1149 cur
->encoding
= oldenc
;
1152 switched_encoding
= 1;
1154 if (ctxt
->escape
== xmlEscapeEntities
)
1155 ctxt
->escape
= NULL
;
1156 if (ctxt
->escapeAttr
== xmlEscapeEntities
)
1157 ctxt
->escapeAttr
= NULL
;
1162 * Save the XML declaration
1164 if ((ctxt
->options
& XML_SAVE_NO_DECL
) == 0) {
1165 xmlOutputBufferWrite(buf
, 14, "<?xml version=");
1166 if (cur
->version
!= NULL
)
1167 xmlBufWriteQuotedString(buf
->buffer
, cur
->version
);
1169 xmlOutputBufferWrite(buf
, 5, "\"1.0\"");
1170 if (encoding
!= NULL
) {
1171 xmlOutputBufferWrite(buf
, 10, " encoding=");
1172 xmlBufWriteQuotedString(buf
->buffer
, (xmlChar
*) encoding
);
1174 switch (cur
->standalone
) {
1176 xmlOutputBufferWrite(buf
, 16, " standalone=\"no\"");
1179 xmlOutputBufferWrite(buf
, 17, " standalone=\"yes\"");
1182 xmlOutputBufferWrite(buf
, 3, "?>\n");
1185 #ifdef LIBXML_HTML_ENABLED
1186 if (ctxt
->options
& XML_SAVE_XHTML
)
1188 if ((ctxt
->options
& XML_SAVE_NO_XHTML
) == 0) {
1189 dtd
= xmlGetIntSubset(cur
);
1191 is_xhtml
= xmlIsXHTML(dtd
->SystemID
, dtd
->ExternalID
);
1192 if (is_xhtml
< 0) is_xhtml
= 0;
1196 if (cur
->children
!= NULL
) {
1197 xmlNodePtr child
= cur
->children
;
1199 while (child
!= NULL
) {
1201 #ifdef LIBXML_HTML_ENABLED
1203 xhtmlNodeDumpOutput(ctxt
, child
);
1206 xmlNodeDumpOutputInternal(ctxt
, child
);
1207 if ((child
->type
!= XML_XINCLUDE_START
) &&
1208 (child
->type
!= XML_XINCLUDE_END
))
1209 xmlOutputBufferWrite(buf
, 1, "\n");
1210 child
= child
->next
;
1216 * Restore the state of the saving context at the end of the document
1218 if ((switched_encoding
) && (oldctxtenc
== NULL
)) {
1219 xmlSaveClearEncoding(ctxt
);
1220 ctxt
->escape
= oldescape
;
1221 ctxt
->escapeAttr
= oldescapeAttr
;
1223 cur
->encoding
= oldenc
;
1227 #ifdef LIBXML_HTML_ENABLED
1228 /************************************************************************
1230 * Functions specific to XHTML serialization *
1232 ************************************************************************/
1238 * Check if a node is an empty xhtml node
1240 * Returns 1 if the node is an empty node, 0 if not and -1 in case of error
1243 xhtmlIsEmpty(xmlNodePtr node
) {
1246 if (node
->type
!= XML_ELEMENT_NODE
)
1248 if ((node
->ns
!= NULL
) && (!xmlStrEqual(node
->ns
->href
, XHTML_NS_NAME
)))
1250 if (node
->children
!= NULL
)
1252 switch (node
->name
[0]) {
1254 if (xmlStrEqual(node
->name
, BAD_CAST
"area"))
1258 if (xmlStrEqual(node
->name
, BAD_CAST
"br"))
1260 if (xmlStrEqual(node
->name
, BAD_CAST
"base"))
1262 if (xmlStrEqual(node
->name
, BAD_CAST
"basefont"))
1266 if (xmlStrEqual(node
->name
, BAD_CAST
"col"))
1270 if (xmlStrEqual(node
->name
, BAD_CAST
"frame"))
1274 if (xmlStrEqual(node
->name
, BAD_CAST
"hr"))
1278 if (xmlStrEqual(node
->name
, BAD_CAST
"img"))
1280 if (xmlStrEqual(node
->name
, BAD_CAST
"input"))
1282 if (xmlStrEqual(node
->name
, BAD_CAST
"isindex"))
1286 if (xmlStrEqual(node
->name
, BAD_CAST
"link"))
1290 if (xmlStrEqual(node
->name
, BAD_CAST
"meta"))
1294 if (xmlStrEqual(node
->name
, BAD_CAST
"param"))
1302 * xhtmlAttrListDumpOutput:
1303 * @cur: the first attribute pointer
1305 * Dump a list of XML attributes
1308 xhtmlAttrListDumpOutput(xmlSaveCtxtPtr ctxt
, xmlAttrPtr cur
) {
1309 xmlAttrPtr xml_lang
= NULL
;
1310 xmlAttrPtr lang
= NULL
;
1311 xmlAttrPtr name
= NULL
;
1312 xmlAttrPtr id
= NULL
;
1314 xmlOutputBufferPtr buf
;
1316 if (cur
== NULL
) return;
1318 parent
= cur
->parent
;
1319 while (cur
!= NULL
) {
1320 if ((cur
->ns
== NULL
) && (xmlStrEqual(cur
->name
, BAD_CAST
"id")))
1323 if ((cur
->ns
== NULL
) && (xmlStrEqual(cur
->name
, BAD_CAST
"name")))
1326 if ((cur
->ns
== NULL
) && (xmlStrEqual(cur
->name
, BAD_CAST
"lang")))
1329 if ((cur
->ns
!= NULL
) && (xmlStrEqual(cur
->name
, BAD_CAST
"lang")) &&
1330 (xmlStrEqual(cur
->ns
->prefix
, BAD_CAST
"xml")))
1332 else if ((cur
->ns
== NULL
) &&
1333 ((cur
->children
== NULL
) ||
1334 (cur
->children
->content
== NULL
) ||
1335 (cur
->children
->content
[0] == 0)) &&
1336 (htmlIsBooleanAttr(cur
->name
))) {
1337 if (cur
->children
!= NULL
)
1338 xmlFreeNode(cur
->children
);
1339 cur
->children
= xmlNewDocText(cur
->doc
, cur
->name
);
1340 if (cur
->children
!= NULL
)
1341 cur
->children
->parent
= (xmlNodePtr
) cur
;
1343 xmlAttrDumpOutput(ctxt
, cur
);
1349 if ((name
!= NULL
) && (id
== NULL
)) {
1350 if ((parent
!= NULL
) && (parent
->name
!= NULL
) &&
1351 ((xmlStrEqual(parent
->name
, BAD_CAST
"a")) ||
1352 (xmlStrEqual(parent
->name
, BAD_CAST
"p")) ||
1353 (xmlStrEqual(parent
->name
, BAD_CAST
"div")) ||
1354 (xmlStrEqual(parent
->name
, BAD_CAST
"img")) ||
1355 (xmlStrEqual(parent
->name
, BAD_CAST
"map")) ||
1356 (xmlStrEqual(parent
->name
, BAD_CAST
"applet")) ||
1357 (xmlStrEqual(parent
->name
, BAD_CAST
"form")) ||
1358 (xmlStrEqual(parent
->name
, BAD_CAST
"frame")) ||
1359 (xmlStrEqual(parent
->name
, BAD_CAST
"iframe")))) {
1360 xmlOutputBufferWrite(buf
, 5, " id=\"");
1361 xmlAttrSerializeContent(buf
, name
);
1362 xmlOutputBufferWrite(buf
, 1, "\"");
1368 if ((lang
!= NULL
) && (xml_lang
== NULL
)) {
1369 xmlOutputBufferWrite(buf
, 11, " xml:lang=\"");
1370 xmlAttrSerializeContent(buf
, lang
);
1371 xmlOutputBufferWrite(buf
, 1, "\"");
1373 if ((xml_lang
!= NULL
) && (lang
== NULL
)) {
1374 xmlOutputBufferWrite(buf
, 7, " lang=\"");
1375 xmlAttrSerializeContent(buf
, xml_lang
);
1376 xmlOutputBufferWrite(buf
, 1, "\"");
1381 * xhtmlNodeDumpOutput:
1382 * @buf: the XML buffer output
1383 * @doc: the XHTML document
1384 * @cur: the current node
1385 * @level: the imbrication level for indenting
1386 * @format: is formatting allowed
1387 * @encoding: an optional encoding string
1389 * Dump an XHTML node, recursive behaviour, children are printed too.
1392 xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt
, xmlNodePtr cur
) {
1393 int format
= ctxt
->format
, addmeta
;
1394 xmlNodePtr tmp
, root
, unformattedNode
= NULL
;
1395 xmlChar
*start
, *end
;
1396 xmlOutputBufferPtr buf
= ctxt
->buf
;
1398 if (cur
== NULL
) return;
1402 switch (cur
->type
) {
1403 case XML_DOCUMENT_NODE
:
1404 case XML_HTML_DOCUMENT_NODE
:
1405 xmlDocContentDumpOutput(ctxt
, (xmlDocPtr
) cur
);
1408 case XML_NAMESPACE_DECL
:
1409 xmlNsDumpOutputCtxt(ctxt
, (xmlNsPtr
) cur
);
1413 xmlDtdDumpOutput(ctxt
, (xmlDtdPtr
) cur
);
1416 case XML_DOCUMENT_FRAG_NODE
:
1417 if (cur
->children
) {
1418 cur
= cur
->children
;
1423 case XML_ELEMENT_DECL
:
1424 xmlBufDumpElementDecl(buf
->buffer
, (xmlElementPtr
) cur
);
1427 case XML_ATTRIBUTE_DECL
:
1428 xmlBufDumpAttributeDecl(buf
->buffer
, (xmlAttributePtr
) cur
);
1431 case XML_ENTITY_DECL
:
1432 xmlBufDumpEntityDecl(buf
->buffer
, (xmlEntityPtr
) cur
);
1435 case XML_ELEMENT_NODE
:
1438 if ((cur
!= root
) && (ctxt
->format
== 1) && (xmlIndentTreeOutput
))
1439 xmlOutputBufferWrite(buf
, ctxt
->indent_size
*
1440 (ctxt
->level
> ctxt
->indent_nr
?
1441 ctxt
->indent_nr
: ctxt
->level
),
1444 xmlOutputBufferWrite(buf
, 1, "<");
1445 if ((cur
->ns
!= NULL
) && (cur
->ns
->prefix
!= NULL
)) {
1446 xmlOutputBufferWriteString(buf
, (const char *)cur
->ns
->prefix
);
1447 xmlOutputBufferWrite(buf
, 1, ":");
1450 xmlOutputBufferWriteString(buf
, (const char *)cur
->name
);
1452 xmlNsListDumpOutputCtxt(ctxt
, cur
->nsDef
);
1453 if ((xmlStrEqual(cur
->name
, BAD_CAST
"html") &&
1454 (cur
->ns
== NULL
) && (cur
->nsDef
== NULL
))) {
1456 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
1458 xmlOutputBufferWriteString(buf
,
1459 " xmlns=\"http://www.w3.org/1999/xhtml\"");
1461 if (cur
->properties
!= NULL
)
1462 xhtmlAttrListDumpOutput(ctxt
, cur
->properties
);
1464 if ((cur
->parent
!= NULL
) &&
1465 (cur
->parent
->parent
== (xmlNodePtr
) cur
->doc
) &&
1466 xmlStrEqual(cur
->name
, BAD_CAST
"head") &&
1467 xmlStrEqual(cur
->parent
->name
, BAD_CAST
"html")) {
1469 tmp
= cur
->children
;
1470 while (tmp
!= NULL
) {
1471 if (xmlStrEqual(tmp
->name
, BAD_CAST
"meta")) {
1474 httpequiv
= xmlGetProp(tmp
, BAD_CAST
"http-equiv");
1475 if (httpequiv
!= NULL
) {
1476 if (xmlStrcasecmp(httpequiv
,
1477 BAD_CAST
"Content-Type") == 0) {
1490 if (cur
->children
== NULL
) {
1491 if (((cur
->ns
== NULL
) || (cur
->ns
->prefix
== NULL
)) &&
1492 ((xhtmlIsEmpty(cur
) == 1) && (addmeta
== 0))) {
1494 * C.2. Empty Elements
1496 xmlOutputBufferWrite(buf
, 3, " />");
1499 xmlOutputBufferWrite(buf
, 1, ">");
1500 if (ctxt
->format
== 1) {
1501 xmlOutputBufferWrite(buf
, 1, "\n");
1502 if (xmlIndentTreeOutput
)
1503 xmlOutputBufferWrite(buf
, ctxt
->indent_size
*
1504 (ctxt
->level
+ 1 > ctxt
->indent_nr
?
1505 ctxt
->indent_nr
: ctxt
->level
+ 1),
1508 xmlOutputBufferWriteString(buf
,
1509 "<meta http-equiv=\"Content-Type\" "
1510 "content=\"text/html; charset=");
1511 if (ctxt
->encoding
) {
1512 xmlOutputBufferWriteString(buf
,
1513 (const char *)ctxt
->encoding
);
1515 xmlOutputBufferWrite(buf
, 5, "UTF-8");
1517 xmlOutputBufferWrite(buf
, 4, "\" />");
1518 if (ctxt
->format
== 1)
1519 xmlOutputBufferWrite(buf
, 1, "\n");
1521 xmlOutputBufferWrite(buf
, 1, ">");
1524 * C.3. Element Minimization and Empty Element Content
1526 xmlOutputBufferWrite(buf
, 2, "</");
1527 if ((cur
->ns
!= NULL
) && (cur
->ns
->prefix
!= NULL
)) {
1528 xmlOutputBufferWriteString(buf
,
1529 (const char *)cur
->ns
->prefix
);
1530 xmlOutputBufferWrite(buf
, 1, ":");
1532 xmlOutputBufferWriteString(buf
, (const char *)cur
->name
);
1533 xmlOutputBufferWrite(buf
, 1, ">");
1536 xmlOutputBufferWrite(buf
, 1, ">");
1538 if (ctxt
->format
== 1) {
1539 xmlOutputBufferWrite(buf
, 1, "\n");
1540 if (xmlIndentTreeOutput
)
1541 xmlOutputBufferWrite(buf
, ctxt
->indent_size
*
1542 (ctxt
->level
+ 1 > ctxt
->indent_nr
?
1543 ctxt
->indent_nr
: ctxt
->level
+ 1),
1546 xmlOutputBufferWriteString(buf
,
1547 "<meta http-equiv=\"Content-Type\" "
1548 "content=\"text/html; charset=");
1549 if (ctxt
->encoding
) {
1550 xmlOutputBufferWriteString(buf
,
1551 (const char *)ctxt
->encoding
);
1553 xmlOutputBufferWrite(buf
, 5, "UTF-8");
1555 xmlOutputBufferWrite(buf
, 4, "\" />");
1558 if (ctxt
->format
== 1) {
1559 tmp
= cur
->children
;
1560 while (tmp
!= NULL
) {
1561 if ((tmp
->type
== XML_TEXT_NODE
) ||
1562 (tmp
->type
== XML_ENTITY_REF_NODE
)) {
1563 unformattedNode
= cur
;
1571 if (ctxt
->format
== 1) xmlOutputBufferWrite(buf
, 1, "\n");
1572 if (ctxt
->level
>= 0) ctxt
->level
++;
1573 cur
= cur
->children
;
1580 if (cur
->content
== NULL
)
1582 if ((cur
->name
== xmlStringText
) ||
1583 (cur
->name
!= xmlStringTextNoenc
)) {
1584 xmlOutputBufferWriteEscape(buf
, cur
->content
, ctxt
->escape
);
1587 * Disable escaping, needed for XSLT
1589 xmlOutputBufferWriteString(buf
, (const char *) cur
->content
);
1594 if (cur
->content
!= NULL
) {
1595 xmlOutputBufferWrite(buf
, 2, "<?");
1596 xmlOutputBufferWriteString(buf
, (const char *)cur
->name
);
1597 if (cur
->content
!= NULL
) {
1598 xmlOutputBufferWrite(buf
, 1, " ");
1599 xmlOutputBufferWriteString(buf
,
1600 (const char *)cur
->content
);
1602 xmlOutputBufferWrite(buf
, 2, "?>");
1604 xmlOutputBufferWrite(buf
, 2, "<?");
1605 xmlOutputBufferWriteString(buf
, (const char *)cur
->name
);
1606 xmlOutputBufferWrite(buf
, 2, "?>");
1610 case XML_COMMENT_NODE
:
1611 if (cur
->content
!= NULL
) {
1612 xmlOutputBufferWrite(buf
, 4, "<!--");
1613 xmlOutputBufferWriteString(buf
, (const char *)cur
->content
);
1614 xmlOutputBufferWrite(buf
, 3, "-->");
1618 case XML_ENTITY_REF_NODE
:
1619 xmlOutputBufferWrite(buf
, 1, "&");
1620 xmlOutputBufferWriteString(buf
, (const char *)cur
->name
);
1621 xmlOutputBufferWrite(buf
, 1, ";");
1624 case XML_CDATA_SECTION_NODE
:
1625 if (cur
->content
== NULL
|| *cur
->content
== '\0') {
1626 xmlOutputBufferWrite(buf
, 12, "<![CDATA[]]>");
1628 start
= end
= cur
->content
;
1629 while (*end
!= '\0') {
1630 if (*end
== ']' && *(end
+ 1) == ']' &&
1631 *(end
+ 2) == '>') {
1633 xmlOutputBufferWrite(buf
, 9, "<![CDATA[");
1634 xmlOutputBufferWrite(buf
, end
- start
,
1635 (const char *)start
);
1636 xmlOutputBufferWrite(buf
, 3, "]]>");
1642 xmlOutputBufferWrite(buf
, 9, "<![CDATA[");
1643 xmlOutputBufferWriteString(buf
, (const char *)start
);
1644 xmlOutputBufferWrite(buf
, 3, "]]>");
1649 case XML_ATTRIBUTE_NODE
:
1650 xmlAttrDumpOutput(ctxt
, (xmlAttrPtr
) cur
);
1660 if (ctxt
->format
== 1)
1661 xmlOutputBufferWrite(buf
, 1, "\n");
1662 if (cur
->next
!= NULL
) {
1668 * The parent should never be NULL here but we want to handle
1669 * corrupted documents gracefully.
1671 if (cur
->parent
== NULL
)
1675 if (cur
->type
== XML_ELEMENT_NODE
) {
1676 if (ctxt
->level
> 0) ctxt
->level
--;
1677 if ((xmlIndentTreeOutput
) && (ctxt
->format
== 1))
1678 xmlOutputBufferWrite(buf
, ctxt
->indent_size
*
1679 (ctxt
->level
> ctxt
->indent_nr
?
1680 ctxt
->indent_nr
: ctxt
->level
),
1683 xmlOutputBufferWrite(buf
, 2, "</");
1684 if ((cur
->ns
!= NULL
) && (cur
->ns
->prefix
!= NULL
)) {
1685 xmlOutputBufferWriteString(buf
,
1686 (const char *)cur
->ns
->prefix
);
1687 xmlOutputBufferWrite(buf
, 1, ":");
1690 xmlOutputBufferWriteString(buf
, (const char *)cur
->name
);
1691 xmlOutputBufferWrite(buf
, 1, ">");
1693 if (cur
== unformattedNode
) {
1694 ctxt
->format
= format
;
1695 unformattedNode
= NULL
;
1703 /************************************************************************
1705 * Public entry points *
1707 ************************************************************************/
1711 * @fd: a file descriptor number
1712 * @encoding: the encoding name to use or NULL
1713 * @options: a set of xmlSaveOptions
1715 * Create a document saving context serializing to a file descriptor
1716 * with the encoding and the options given.
1718 * Returns a new serialization context or NULL in case of error.
1721 xmlSaveToFd(int fd
, const char *encoding
, int options
)
1725 ret
= xmlNewSaveCtxt(encoding
, options
);
1726 if (ret
== NULL
) return(NULL
);
1727 ret
->buf
= xmlOutputBufferCreateFd(fd
, ret
->handler
);
1728 if (ret
->buf
== NULL
) {
1729 xmlCharEncCloseFunc(ret
->handler
);
1730 xmlFreeSaveCtxt(ret
);
1737 * xmlSaveToFilename:
1738 * @filename: a file name or an URL
1739 * @encoding: the encoding name to use or NULL
1740 * @options: a set of xmlSaveOptions
1742 * Create a document saving context serializing to a filename or possibly
1743 * to an URL (but this is less reliable) with the encoding and the options
1746 * Returns a new serialization context or NULL in case of error.
1749 xmlSaveToFilename(const char *filename
, const char *encoding
, int options
)
1752 int compression
= 0; /* TODO handle compression option */
1754 ret
= xmlNewSaveCtxt(encoding
, options
);
1755 if (ret
== NULL
) return(NULL
);
1756 ret
->buf
= xmlOutputBufferCreateFilename(filename
, ret
->handler
,
1758 if (ret
->buf
== NULL
) {
1759 xmlCharEncCloseFunc(ret
->handler
);
1760 xmlFreeSaveCtxt(ret
);
1769 * @encoding: the encoding name to use or NULL
1770 * @options: a set of xmlSaveOptions
1772 * Create a document saving context serializing to a buffer
1773 * with the encoding and the options given
1775 * Returns a new serialization context or NULL in case of error.
1779 xmlSaveToBuffer(xmlBufferPtr buffer
, const char *encoding
, int options
)
1783 ret
= xmlNewSaveCtxt(encoding
, options
);
1784 if (ret
== NULL
) return(NULL
);
1785 ret
->buf
= xmlOutputBufferCreateBuffer(buffer
, ret
->handler
);
1786 if (ret
->buf
== NULL
) {
1787 xmlCharEncCloseFunc(ret
->handler
);
1788 xmlFreeSaveCtxt(ret
);
1796 * @iowrite: an I/O write function
1797 * @ioclose: an I/O close function
1798 * @ioctx: an I/O handler
1799 * @encoding: the encoding name to use or NULL
1800 * @options: a set of xmlSaveOptions
1802 * Create a document saving context serializing to a file descriptor
1803 * with the encoding and the options given
1805 * Returns a new serialization context or NULL in case of error.
1808 xmlSaveToIO(xmlOutputWriteCallback iowrite
,
1809 xmlOutputCloseCallback ioclose
,
1810 void *ioctx
, const char *encoding
, int options
)
1814 ret
= xmlNewSaveCtxt(encoding
, options
);
1815 if (ret
== NULL
) return(NULL
);
1816 ret
->buf
= xmlOutputBufferCreateIO(iowrite
, ioclose
, ioctx
, ret
->handler
);
1817 if (ret
->buf
== NULL
) {
1818 xmlCharEncCloseFunc(ret
->handler
);
1819 xmlFreeSaveCtxt(ret
);
1827 * @ctxt: a document saving context
1830 * Save a full document to a saving context
1831 * TODO: The function is not fully implemented yet as it does not return the
1832 * byte count but 0 instead
1834 * Returns the number of byte written or -1 in case of error
1837 xmlSaveDoc(xmlSaveCtxtPtr ctxt
, xmlDocPtr doc
)
1841 if ((ctxt
== NULL
) || (doc
== NULL
)) return(-1);
1842 if (xmlDocContentDumpOutput(ctxt
, doc
) < 0)
1849 * @ctxt: a document saving context
1850 * @node: the top node of the subtree to save
1852 * Save a subtree starting at the node parameter to a saving context
1853 * TODO: The function is not fully implemented yet as it does not return the
1854 * byte count but 0 instead
1856 * Returns the number of byte written or -1 in case of error
1859 xmlSaveTree(xmlSaveCtxtPtr ctxt
, xmlNodePtr cur
)
1863 if ((ctxt
== NULL
) || (cur
== NULL
)) return(-1);
1864 #ifdef LIBXML_HTML_ENABLED
1865 if (ctxt
->options
& XML_SAVE_XHTML
) {
1866 xhtmlNodeDumpOutput(ctxt
, cur
);
1869 if (((cur
->type
!= XML_NAMESPACE_DECL
) && (cur
->doc
!= NULL
) &&
1870 (cur
->doc
->type
== XML_HTML_DOCUMENT_NODE
) &&
1871 ((ctxt
->options
& XML_SAVE_AS_XML
) == 0)) ||
1872 (ctxt
->options
& XML_SAVE_AS_HTML
)) {
1873 htmlNodeDumpOutputInternal(ctxt
, cur
);
1877 xmlNodeDumpOutputInternal(ctxt
, cur
);
1883 * @ctxt: a document saving context
1885 * Flush a document saving context, i.e. make sure that all bytes have
1888 * Returns the number of byte written or -1 in case of error.
1891 xmlSaveFlush(xmlSaveCtxtPtr ctxt
)
1893 if (ctxt
== NULL
) return(-1);
1894 if (ctxt
->buf
== NULL
) return(-1);
1895 return(xmlOutputBufferFlush(ctxt
->buf
));
1900 * @ctxt: a document saving context
1902 * Close a document saving context, i.e. make sure that all bytes have
1903 * been output and free the associated data.
1905 * Returns the number of byte written or -1 in case of error.
1908 xmlSaveClose(xmlSaveCtxtPtr ctxt
)
1912 if (ctxt
== NULL
) return(-1);
1913 ret
= xmlSaveFlush(ctxt
);
1914 xmlFreeSaveCtxt(ctxt
);
1920 * @ctxt: a document saving context
1921 * @escape: the escaping function
1923 * Set a custom escaping function to be used for text in element content
1925 * Returns 0 if successful or -1 in case of error.
1928 xmlSaveSetEscape(xmlSaveCtxtPtr ctxt
, xmlCharEncodingOutputFunc escape
)
1930 if (ctxt
== NULL
) return(-1);
1931 ctxt
->escape
= escape
;
1936 * xmlSaveSetAttrEscape:
1937 * @ctxt: a document saving context
1938 * @escape: the escaping function
1940 * Set a custom escaping function to be used for text in attribute content
1942 * Returns 0 if successful or -1 in case of error.
1945 xmlSaveSetAttrEscape(xmlSaveCtxtPtr ctxt
, xmlCharEncodingOutputFunc escape
)
1947 if (ctxt
== NULL
) return(-1);
1948 ctxt
->escapeAttr
= escape
;
1952 /************************************************************************
1954 * Public entry points based on buffers *
1956 ************************************************************************/
1959 * xmlBufAttrSerializeTxtContent:
1960 * @buf: and xmlBufPtr output
1961 * @doc: the document
1962 * @attr: the attribute node
1963 * @string: the text content
1965 * Serialize text attribute values to an xmlBufPtr
1968 xmlBufAttrSerializeTxtContent(xmlBufPtr buf
, xmlDocPtr doc
,
1969 xmlAttrPtr attr
, const xmlChar
* string
)
1971 xmlChar
*base
, *cur
;
1975 base
= cur
= (xmlChar
*) string
;
1979 xmlBufAdd(buf
, base
, cur
- base
);
1980 xmlBufAdd(buf
, BAD_CAST
" ", 5);
1983 } else if (*cur
== '\r') {
1985 xmlBufAdd(buf
, base
, cur
- base
);
1986 xmlBufAdd(buf
, BAD_CAST
" ", 5);
1989 } else if (*cur
== '\t') {
1991 xmlBufAdd(buf
, base
, cur
- base
);
1992 xmlBufAdd(buf
, BAD_CAST
"	", 4);
1995 } else if (*cur
== '"') {
1997 xmlBufAdd(buf
, base
, cur
- base
);
1998 xmlBufAdd(buf
, BAD_CAST
""", 6);
2001 } else if (*cur
== '<') {
2003 xmlBufAdd(buf
, base
, cur
- base
);
2004 xmlBufAdd(buf
, BAD_CAST
"<", 4);
2007 } else if (*cur
== '>') {
2009 xmlBufAdd(buf
, base
, cur
- base
);
2010 xmlBufAdd(buf
, BAD_CAST
">", 4);
2013 } else if (*cur
== '&') {
2015 xmlBufAdd(buf
, base
, cur
- base
);
2016 xmlBufAdd(buf
, BAD_CAST
"&", 5);
2019 } else if ((*cur
>= 0x80) && (cur
[1] != 0) &&
2020 ((doc
== NULL
) || (doc
->encoding
== NULL
))) {
2022 * We assume we have UTF-8 content.
2024 unsigned char tmp
[12];
2028 xmlBufAdd(buf
, base
, cur
- base
);
2030 xmlSaveErr(XML_SAVE_NOT_UTF8
, (xmlNodePtr
) attr
, NULL
);
2031 xmlSerializeHexCharRef(tmp
, *cur
);
2032 xmlBufAdd(buf
, (xmlChar
*) tmp
, -1);
2036 } else if (*cur
< 0xE0) {
2037 val
= (cur
[0]) & 0x1F;
2039 val
|= (cur
[1]) & 0x3F;
2041 } else if ((*cur
< 0xF0) && (cur
[2] != 0)) {
2042 val
= (cur
[0]) & 0x0F;
2044 val
|= (cur
[1]) & 0x3F;
2046 val
|= (cur
[2]) & 0x3F;
2048 } else if ((*cur
< 0xF8) && (cur
[2] != 0) && (cur
[3] != 0)) {
2049 val
= (cur
[0]) & 0x07;
2051 val
|= (cur
[1]) & 0x3F;
2053 val
|= (cur
[2]) & 0x3F;
2055 val
|= (cur
[3]) & 0x3F;
2058 if ((l
== 1) || (!IS_CHAR(val
))) {
2059 xmlSaveErr(XML_SAVE_CHAR_INVALID
, (xmlNodePtr
) attr
, NULL
);
2060 xmlSerializeHexCharRef(tmp
, *cur
);
2061 xmlBufAdd(buf
, (xmlChar
*) tmp
, -1);
2067 * We could do multiple things here. Just save
2070 xmlSerializeHexCharRef(tmp
, val
);
2071 xmlBufAdd(buf
, (xmlChar
*) tmp
, -1);
2079 xmlBufAdd(buf
, base
, cur
- base
);
2083 * xmlAttrSerializeTxtContent:
2084 * @buf: the XML buffer output
2085 * @doc: the document
2086 * @attr: the attribute node
2087 * @string: the text content
2089 * Serialize text attribute values to an xml simple buffer
2092 xmlAttrSerializeTxtContent(xmlBufferPtr buf
, xmlDocPtr doc
,
2093 xmlAttrPtr attr
, const xmlChar
* string
)
2097 if ((buf
== NULL
) || (string
== NULL
))
2099 buffer
= xmlBufFromBuffer(buf
);
2102 xmlBufAttrSerializeTxtContent(buffer
, doc
, attr
, string
);
2103 xmlBufBackToBuffer(buffer
);
2108 * @buf: the XML buffer output
2109 * @doc: the document
2110 * @cur: the current node
2111 * @level: the imbrication level for indenting
2112 * @format: is formatting allowed
2114 * Dump an XML node, recursive behaviour,children are printed too.
2115 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
2116 * or xmlKeepBlanksDefault(0) was called.
2117 * Since this is using xmlBuffer structures it is limited to 2GB and somehow
2118 * deprecated, use xmlNodeDumpOutput() instead.
2120 * Returns the number of bytes written to the buffer or -1 in case of error
2123 xmlNodeDump(xmlBufferPtr buf
, xmlDocPtr doc
, xmlNodePtr cur
, int level
,
2129 if ((buf
== NULL
) || (cur
== NULL
))
2131 buffer
= xmlBufFromBuffer(buf
);
2134 ret
= xmlBufNodeDump(buffer
, doc
, cur
, level
, format
);
2135 xmlBufBackToBuffer(buffer
);
2143 * @buf: the XML buffer output
2144 * @doc: the document
2145 * @cur: the current node
2146 * @level: the imbrication level for indenting
2147 * @format: is formatting allowed
2149 * Dump an XML node, recursive behaviour,children are printed too.
2150 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
2151 * or xmlKeepBlanksDefault(0) was called
2153 * Returns the number of bytes written to the buffer, in case of error 0
2154 * is returned or @buf stores the error
2158 xmlBufNodeDump(xmlBufPtr buf
, xmlDocPtr doc
, xmlNodePtr cur
, int level
,
2163 xmlOutputBufferPtr outbuf
;
2170 xmlGenericError(xmlGenericErrorContext
,
2171 "xmlNodeDump : node == NULL\n");
2177 xmlGenericError(xmlGenericErrorContext
,
2178 "xmlNodeDump : buf == NULL\n");
2182 outbuf
= (xmlOutputBufferPtr
) xmlMalloc(sizeof(xmlOutputBuffer
));
2183 if (outbuf
== NULL
) {
2184 xmlSaveErrMemory("creating buffer");
2187 memset(outbuf
, 0, (size_t) sizeof(xmlOutputBuffer
));
2188 outbuf
->buffer
= buf
;
2189 outbuf
->encoder
= NULL
;
2190 outbuf
->writecallback
= NULL
;
2191 outbuf
->closecallback
= NULL
;
2192 outbuf
->context
= NULL
;
2193 outbuf
->written
= 0;
2195 use
= xmlBufUse(buf
);
2196 oldalloc
= xmlBufGetAllocationScheme(buf
);
2197 xmlBufSetAllocationScheme(buf
, XML_BUFFER_ALLOC_DOUBLEIT
);
2198 xmlNodeDumpOutput(outbuf
, doc
, cur
, level
, format
, NULL
);
2199 xmlBufSetAllocationScheme(buf
, oldalloc
);
2201 ret
= xmlBufUse(buf
) - use
;
2207 * @f: the FILE * for the output
2208 * @doc: the document
2209 * @cur: the current node
2211 * Dump an XML/HTML node, recursive behaviour, children are printed too.
2214 xmlElemDump(FILE * f
, xmlDocPtr doc
, xmlNodePtr cur
)
2216 xmlOutputBufferPtr outbuf
;
2222 xmlGenericError(xmlGenericErrorContext
,
2223 "xmlElemDump : cur == NULL\n");
2229 xmlGenericError(xmlGenericErrorContext
,
2230 "xmlElemDump : doc == NULL\n");
2234 outbuf
= xmlOutputBufferCreateFile(f
, NULL
);
2237 if ((doc
!= NULL
) && (doc
->type
== XML_HTML_DOCUMENT_NODE
)) {
2238 #ifdef LIBXML_HTML_ENABLED
2239 htmlNodeDumpOutput(outbuf
, doc
, cur
, NULL
);
2241 xmlSaveErr(XML_ERR_INTERNAL_ERROR
, cur
, "HTML support not compiled in\n");
2242 #endif /* LIBXML_HTML_ENABLED */
2244 xmlNodeDumpOutput(outbuf
, doc
, cur
, 0, 1, NULL
);
2245 xmlOutputBufferClose(outbuf
);
2248 /************************************************************************
2250 * Saving functions front-ends *
2252 ************************************************************************/
2255 * xmlNodeDumpOutput:
2256 * @buf: the XML buffer output
2257 * @doc: the document
2258 * @cur: the current node
2259 * @level: the imbrication level for indenting
2260 * @format: is formatting allowed
2261 * @encoding: an optional encoding string
2263 * Dump an XML node, recursive behaviour, children are printed too.
2264 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
2265 * or xmlKeepBlanksDefault(0) was called
2268 xmlNodeDumpOutput(xmlOutputBufferPtr buf
, xmlDocPtr doc
, xmlNodePtr cur
,
2269 int level
, int format
, const char *encoding
)
2272 #ifdef LIBXML_HTML_ENABLED
2279 if ((buf
== NULL
) || (cur
== NULL
)) return;
2281 if (encoding
== NULL
)
2284 memset(&ctxt
, 0, sizeof(ctxt
));
2287 ctxt
.format
= format
? 1 : 0;
2288 ctxt
.encoding
= (const xmlChar
*) encoding
;
2289 xmlSaveCtxtInit(&ctxt
);
2290 ctxt
.options
|= XML_SAVE_AS_XML
;
2292 #ifdef LIBXML_HTML_ENABLED
2293 dtd
= xmlGetIntSubset(doc
);
2295 is_xhtml
= xmlIsXHTML(dtd
->SystemID
, dtd
->ExternalID
);
2301 xhtmlNodeDumpOutput(&ctxt
, cur
);
2304 xmlNodeDumpOutputInternal(&ctxt
, cur
);
2308 * xmlDocDumpFormatMemoryEnc:
2309 * @out_doc: Document to generate XML text from
2310 * @doc_txt_ptr: Memory pointer for allocated XML text
2311 * @doc_txt_len: Length of the generated XML text
2312 * @txt_encoding: Character encoding to use when generating XML text
2313 * @format: should formatting spaces been added
2315 * Dump the current DOM tree into memory using the character encoding specified
2316 * by the caller. Note it is up to the caller of this function to free the
2317 * allocated memory with xmlFree().
2318 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
2319 * or xmlKeepBlanksDefault(0) was called
2323 xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc
, xmlChar
**doc_txt_ptr
,
2324 int * doc_txt_len
, const char * txt_encoding
,
2328 xmlOutputBufferPtr out_buff
= NULL
;
2329 xmlCharEncodingHandlerPtr conv_hdlr
= NULL
;
2331 if (doc_txt_len
== NULL
) {
2332 doc_txt_len
= &dummy
; /* Continue, caller just won't get length */
2335 if (doc_txt_ptr
== NULL
) {
2340 *doc_txt_ptr
= NULL
;
2343 if (out_doc
== NULL
) {
2344 /* No document, no output */
2349 * Validate the encoding value, if provided.
2350 * This logic is copied from xmlSaveFileEnc.
2353 if (txt_encoding
== NULL
)
2354 txt_encoding
= (const char *) out_doc
->encoding
;
2355 if (txt_encoding
!= NULL
) {
2356 conv_hdlr
= xmlFindCharEncodingHandler(txt_encoding
);
2357 if ( conv_hdlr
== NULL
) {
2358 xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING
, (xmlNodePtr
) out_doc
,
2364 if ((out_buff
= xmlAllocOutputBuffer(conv_hdlr
)) == NULL
) {
2365 xmlSaveErrMemory("creating buffer");
2366 xmlCharEncCloseFunc(conv_hdlr
);
2370 memset(&ctxt
, 0, sizeof(ctxt
));
2371 ctxt
.buf
= out_buff
;
2373 ctxt
.format
= format
? 1 : 0;
2374 ctxt
.encoding
= (const xmlChar
*) txt_encoding
;
2375 xmlSaveCtxtInit(&ctxt
);
2376 ctxt
.options
|= XML_SAVE_AS_XML
;
2377 xmlDocContentDumpOutput(&ctxt
, out_doc
);
2378 xmlOutputBufferFlush(out_buff
);
2379 if (out_buff
->conv
!= NULL
) {
2380 *doc_txt_len
= xmlBufUse(out_buff
->conv
);
2381 *doc_txt_ptr
= xmlStrndup(xmlBufContent(out_buff
->conv
), *doc_txt_len
);
2383 *doc_txt_len
= xmlBufUse(out_buff
->buffer
);
2384 *doc_txt_ptr
= xmlStrndup(xmlBufContent(out_buff
->buffer
),*doc_txt_len
);
2386 (void)xmlOutputBufferClose(out_buff
);
2388 if ((*doc_txt_ptr
== NULL
) && (*doc_txt_len
> 0)) {
2390 xmlSaveErrMemory("creating output");
2398 * @cur: the document
2399 * @mem: OUT: the memory pointer
2400 * @size: OUT: the memory length
2402 * Dump an XML document in memory and return the #xmlChar * and it's size
2403 * in bytes. It's up to the caller to free the memory with xmlFree().
2404 * The resulting byte array is zero terminated, though the last 0 is not
2405 * included in the returned size.
2408 xmlDocDumpMemory(xmlDocPtr cur
, xmlChar
**mem
, int *size
) {
2409 xmlDocDumpFormatMemoryEnc(cur
, mem
, size
, NULL
, 0);
2413 * xmlDocDumpFormatMemory:
2414 * @cur: the document
2415 * @mem: OUT: the memory pointer
2416 * @size: OUT: the memory length
2417 * @format: should formatting spaces been added
2420 * Dump an XML document in memory and return the #xmlChar * and it's size.
2421 * It's up to the caller to free the memory with xmlFree().
2422 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
2423 * or xmlKeepBlanksDefault(0) was called
2426 xmlDocDumpFormatMemory(xmlDocPtr cur
, xmlChar
**mem
, int *size
, int format
) {
2427 xmlDocDumpFormatMemoryEnc(cur
, mem
, size
, NULL
, format
);
2431 * xmlDocDumpMemoryEnc:
2432 * @out_doc: Document to generate XML text from
2433 * @doc_txt_ptr: Memory pointer for allocated XML text
2434 * @doc_txt_len: Length of the generated XML text
2435 * @txt_encoding: Character encoding to use when generating XML text
2437 * Dump the current DOM tree into memory using the character encoding specified
2438 * by the caller. Note it is up to the caller of this function to free the
2439 * allocated memory with xmlFree().
2443 xmlDocDumpMemoryEnc(xmlDocPtr out_doc
, xmlChar
**doc_txt_ptr
,
2444 int * doc_txt_len
, const char * txt_encoding
) {
2445 xmlDocDumpFormatMemoryEnc(out_doc
, doc_txt_ptr
, doc_txt_len
,
2452 * @cur: the document
2453 * @format: should formatting spaces been added
2455 * Dump an XML document to an open FILE.
2457 * returns: the number of bytes written or -1 in case of failure.
2458 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
2459 * or xmlKeepBlanksDefault(0) was called
2462 xmlDocFormatDump(FILE *f
, xmlDocPtr cur
, int format
) {
2464 xmlOutputBufferPtr buf
;
2465 const char * encoding
;
2466 xmlCharEncodingHandlerPtr handler
= NULL
;
2471 xmlGenericError(xmlGenericErrorContext
,
2472 "xmlDocDump : document == NULL\n");
2476 encoding
= (const char *) cur
->encoding
;
2478 if (encoding
!= NULL
) {
2479 handler
= xmlFindCharEncodingHandler(encoding
);
2480 if (handler
== NULL
) {
2481 xmlFree((char *) cur
->encoding
);
2482 cur
->encoding
= NULL
;
2486 buf
= xmlOutputBufferCreateFile(f
, handler
);
2487 if (buf
== NULL
) return(-1);
2488 memset(&ctxt
, 0, sizeof(ctxt
));
2491 ctxt
.format
= format
? 1 : 0;
2492 ctxt
.encoding
= (const xmlChar
*) encoding
;
2493 xmlSaveCtxtInit(&ctxt
);
2494 ctxt
.options
|= XML_SAVE_AS_XML
;
2495 xmlDocContentDumpOutput(&ctxt
, cur
);
2497 ret
= xmlOutputBufferClose(buf
);
2504 * @cur: the document
2506 * Dump an XML document to an open FILE.
2508 * returns: the number of bytes written or -1 in case of failure.
2511 xmlDocDump(FILE *f
, xmlDocPtr cur
) {
2512 return(xmlDocFormatDump (f
, cur
, 0));
2517 * @buf: an output I/O buffer
2518 * @cur: the document
2519 * @encoding: the encoding if any assuming the I/O layer handles the transcoding
2521 * Dump an XML document to an I/O buffer.
2522 * Warning ! This call xmlOutputBufferClose() on buf which is not available
2525 * returns: the number of bytes written or -1 in case of failure.
2528 xmlSaveFileTo(xmlOutputBufferPtr buf
, xmlDocPtr cur
, const char *encoding
) {
2532 if (buf
== NULL
) return(-1);
2534 xmlOutputBufferClose(buf
);
2537 memset(&ctxt
, 0, sizeof(ctxt
));
2541 ctxt
.encoding
= (const xmlChar
*) encoding
;
2542 xmlSaveCtxtInit(&ctxt
);
2543 ctxt
.options
|= XML_SAVE_AS_XML
;
2544 xmlDocContentDumpOutput(&ctxt
, cur
);
2545 ret
= xmlOutputBufferClose(buf
);
2550 * xmlSaveFormatFileTo:
2551 * @buf: an output I/O buffer
2552 * @cur: the document
2553 * @encoding: the encoding if any assuming the I/O layer handles the transcoding
2554 * @format: should formatting spaces been added
2556 * Dump an XML document to an I/O buffer.
2557 * Warning ! This call xmlOutputBufferClose() on buf which is not available
2560 * returns: the number of bytes written or -1 in case of failure.
2563 xmlSaveFormatFileTo(xmlOutputBufferPtr buf
, xmlDocPtr cur
,
2564 const char *encoding
, int format
)
2569 if (buf
== NULL
) return(-1);
2570 if ((cur
== NULL
) ||
2571 ((cur
->type
!= XML_DOCUMENT_NODE
) &&
2572 (cur
->type
!= XML_HTML_DOCUMENT_NODE
))) {
2573 xmlOutputBufferClose(buf
);
2576 memset(&ctxt
, 0, sizeof(ctxt
));
2579 ctxt
.format
= format
? 1 : 0;
2580 ctxt
.encoding
= (const xmlChar
*) encoding
;
2581 xmlSaveCtxtInit(&ctxt
);
2582 ctxt
.options
|= XML_SAVE_AS_XML
;
2583 xmlDocContentDumpOutput(&ctxt
, cur
);
2584 ret
= xmlOutputBufferClose(buf
);
2589 * xmlSaveFormatFileEnc:
2590 * @filename: the filename or URL to output
2591 * @cur: the document being saved
2592 * @encoding: the name of the encoding to use or NULL.
2593 * @format: should formatting spaces be added.
2595 * Dump an XML document to a file or an URL.
2597 * Returns the number of bytes written or -1 in case of error.
2598 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
2599 * or xmlKeepBlanksDefault(0) was called
2602 xmlSaveFormatFileEnc( const char * filename
, xmlDocPtr cur
,
2603 const char * encoding
, int format
) {
2605 xmlOutputBufferPtr buf
;
2606 xmlCharEncodingHandlerPtr handler
= NULL
;
2612 if (encoding
== NULL
)
2613 encoding
= (const char *) cur
->encoding
;
2615 if (encoding
!= NULL
) {
2617 handler
= xmlFindCharEncodingHandler(encoding
);
2618 if (handler
== NULL
)
2622 #ifdef LIBXML_ZLIB_ENABLED
2623 if (cur
->compression
< 0) cur
->compression
= xmlGetCompressMode();
2626 * save the content to a temp buffer.
2628 buf
= xmlOutputBufferCreateFilename(filename
, handler
, cur
->compression
);
2629 if (buf
== NULL
) return(-1);
2630 memset(&ctxt
, 0, sizeof(ctxt
));
2633 ctxt
.format
= format
? 1 : 0;
2634 ctxt
.encoding
= (const xmlChar
*) encoding
;
2635 xmlSaveCtxtInit(&ctxt
);
2636 ctxt
.options
|= XML_SAVE_AS_XML
;
2638 xmlDocContentDumpOutput(&ctxt
, cur
);
2640 ret
= xmlOutputBufferClose(buf
);
2647 * @filename: the filename (or URL)
2648 * @cur: the document
2649 * @encoding: the name of an encoding (or NULL)
2651 * Dump an XML document, converting it to the given encoding
2653 * returns: the number of bytes written or -1 in case of failure.
2656 xmlSaveFileEnc(const char *filename
, xmlDocPtr cur
, const char *encoding
) {
2657 return ( xmlSaveFormatFileEnc( filename
, cur
, encoding
, 0 ) );
2661 * xmlSaveFormatFile:
2662 * @filename: the filename (or URL)
2663 * @cur: the document
2664 * @format: should formatting spaces been added
2666 * Dump an XML document to a file. Will use compression if
2667 * compiled in and enabled. If @filename is "-" the stdout file is
2668 * used. If @format is set then the document will be indented on output.
2669 * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
2670 * or xmlKeepBlanksDefault(0) was called
2672 * returns: the number of bytes written or -1 in case of failure.
2675 xmlSaveFormatFile(const char *filename
, xmlDocPtr cur
, int format
) {
2676 return ( xmlSaveFormatFileEnc( filename
, cur
, NULL
, format
) );
2681 * @filename: the filename (or URL)
2682 * @cur: the document
2684 * Dump an XML document to a file. Will use compression if
2685 * compiled in and enabled. If @filename is "-" the stdout file is
2687 * returns: the number of bytes written or -1 in case of failure.
2690 xmlSaveFile(const char *filename
, xmlDocPtr cur
) {
2691 return(xmlSaveFormatFileEnc(filename
, cur
, NULL
, 0));
2694 #endif /* LIBXML_OUTPUT_ENABLED */