From 60366c5e3e326eb0d5b828ba8bbd81f317cd24e3 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 10 Aug 2015 10:57:06 +0200 Subject: Implement support for suspending/resuming indentation in serializer --- xml/details/genx/genx.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++--- xml/details/genx/genx.h | 18 +++++++++++ xml/serializer | 24 ++++++++++++++ xml/serializer.cxx | 20 ++++++++++++ 4 files changed, 142 insertions(+), 4 deletions(-) (limited to 'xml') diff --git a/xml/details/genx/genx.c b/xml/details/genx/genx.c index 1f2303d..387cc94 100644 --- a/xml/details/genx/genx.c +++ b/xml/details/genx/genx.c @@ -131,6 +131,7 @@ struct genxWriter_rec /* Pretty-printing state */ int ppIndent; int ppDepth; + int ppSuspendDepth; /* Non-0 means we are suspended. */ Boolean ppSimple; /* Canonicalization. */ @@ -693,6 +694,62 @@ int genxGetPrettyPrint(genxWriter w) } /* + * Suspend/resume pretty-printing. + */ +genxStatus genxSuspendPrettyPrint(genxWriter w) +{ + int d = w->ppDepth; + + if (w->ppIndent == 0) + return w->status = GENX_SEQUENCE_ERROR; + + switch (w->sequence) + { + case SEQUENCE_START_TAG: + case SEQUENCE_ATTRIBUTES: + d++; /* No start tag written, still outer depth. */ + case SEQUENCE_CONTENT: + break; + default: + return w->status = GENX_SEQUENCE_ERROR; + } + + if (w->ppSuspendDepth == 0) /* Ignore nested suspend/resume calls. */ + w->ppSuspendDepth = d; + + return w->status; +} + +genxStatus genxResumePrettyPrint(genxWriter w) +{ + int d = w->ppDepth; + + if (w->ppIndent == 0 || w->ppSuspendDepth == 0) + return w->status = GENX_SEQUENCE_ERROR; + + switch (w->sequence) + { + case SEQUENCE_START_TAG: + case SEQUENCE_ATTRIBUTES: + d++; /* No start tag written, still outer depth. */ + case SEQUENCE_CONTENT: + break; + default: + return w->status = GENX_SEQUENCE_ERROR; + } + + if (w->ppSuspendDepth == d) /* Ignore nested suspend/resume calls. */ + w->ppSuspendDepth = 0; + + return w->status; +} + +int genxPrettyPrintSuspended(genxWriter w) +{ + return w->ppSuspendDepth; +} + +/* * get/set canonicalization. */ genxStatus genxSetCanonical(genxWriter w, int flag) @@ -1217,8 +1274,9 @@ genxStatus genxStartDocSender(genxWriter w, genxSender * sender) if (w->ppIndent) { - w->ppSimple = True; w->ppDepth = 0; + w->ppSuspendDepth = 0; + w->ppSimple = True; } return GENX_SUCCESS; @@ -1292,7 +1350,9 @@ static genxStatus writeStartTag(genxWriter w, Boolean close) if (w->ppIndent) { - if (w->ppDepth) + if (w->ppDepth && + /* Suspend depth could be at this element's depth (after ++ below). */ + (w->ppSuspendDepth == 0 || w->ppSuspendDepth > w->ppDepth)) if (writeIndentation (w) != GENX_SUCCESS) return w->status; @@ -1301,6 +1361,15 @@ static genxStatus writeStartTag(genxWriter w, Boolean close) w->ppDepth++; w->ppSimple = True; } + else + { + /* + * Conceptually we incremented/decremented the depth, so check if we + * need to resume pretty-printing. + */ + if (w->ppSuspendDepth > w->ppDepth) + w->ppSuspendDepth = 0; + } } SendCheck(w, "<"); @@ -1789,9 +1858,12 @@ genxStatus genxEndElement(genxWriter w) { w->ppDepth--; - if (!w->ppSimple) + if (!w->ppSimple && w->ppSuspendDepth == 0) if (writeIndentation (w) != GENX_SUCCESS) return w->status; + + if (w->ppSuspendDepth > w->ppDepth) + w->ppSuspendDepth = 0; /* Resume pretty-printing. */ } SendCheck(w, ""); } - if (w->ppIndent) + /* If this element is written while pretty-printing is suspended, + treat it as simple. As an example, think of an XHTML element + for which we suspend pretty-printing before writing the opening + tag and resume it after the closing one. */ + if (w->ppIndent && w->ppSuspendDepth == 0) w->ppSimple = False; /* diff --git a/xml/details/genx/genx.h b/xml/details/genx/genx.h index e55b467..89f0637 100644 --- a/xml/details/genx/genx.h +++ b/xml/details/genx/genx.h @@ -118,6 +118,24 @@ genxStatus genxSetPrettyPrint(genxWriter w, int indentation); int genxGetPrettyPrint(genxWriter w); /* + * Suspend/resume pretty-printing. Pretty-printing can be suspended + * only inside an element and, unless explicitly resumed, it will + * remain suspended until the end of that element. You should only + * explicitly resume pretty-printing at the element nesting level + * of suspension. If pretty-printing is already suspended at an + * outer nesting level, then subsequent calls to suspend/resume + * are ignored. The PrettyPrintSuspended() function can be used + * to check if pretty-printing is currently suspended. If it is + * not, then this function returns 0. Otherwise, it returns the + * level at which pretty-printing was suspended, with root element + * being level 1. + */ +genxStatus genxSuspendPrettyPrint(genxWriter w); +genxStatus genxResumePrettyPrint(genxWriter w); +int genxPrettyPrintSuspended(genxWriter w); + + +/* * Set/get canonicalization. If true, then output explicit closing * tags and sort attributes. Default is false. */ diff --git a/xml/serializer b/xml/serializer index 68e72c3..316a501 100644 --- a/xml/serializer +++ b/xml/serializer @@ -214,6 +214,30 @@ namespace xml bool lookup_namespace_prefix (const std::string& ns, std::string& prefix); + // Suspend/resume indentation. + // + public: + + // Indentation can be suspended only inside an element and, unless + // explicitly resumed, it will remain suspended until the end of + // that element. You should only explicitly resume indentation at + // the element nesting level of suspension. If indentation is already + // suspended at an outer nesting level, then subsequent calls to + // suspend/resume are ignored. The indentation_suspended() function + // can be used to check if indentation is currently suspended. If it + // is not, then this function returns 0. Otherwise, it returns the + // level at which pretty-printing was suspended, with root element + // being level 1. + // + void + suspend_indentation (); + + void + resume_indentation (); + + std::size_t + indentation_suspended () const; + private: void handle_error (genxStatus); diff --git a/xml/serializer.cxx b/xml/serializer.cxx index 775105f..5ed5c5e 100644 --- a/xml/serializer.cxx +++ b/xml/serializer.cxx @@ -273,4 +273,24 @@ namespace xml p = reinterpret_cast (genxGetNamespacePrefix (gns)); return true; } + + void serializer:: + suspend_indentation () + { + if (genxStatus e = genxSuspendPrettyPrint (s_)) + handle_error (e); + } + + void serializer:: + resume_indentation () + { + if (genxStatus e = genxResumePrettyPrint (s_)) + handle_error (e); + } + + size_t serializer:: + indentation_suspended () const + { + return static_cast (genxPrettyPrintSuspended (s_)); + } } -- cgit v1.1