aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-08-10 10:57:06 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-08-10 10:57:06 +0200
commit60366c5e3e326eb0d5b828ba8bbd81f317cd24e3 (patch)
tree94e5183599242668deadf8f6b415f3ef05058d63
parente8e3ce68f3ea3ccbfaaa9a189b46676b91261a65 (diff)
Implement support for suspending/resuming indentation in serializer
-rw-r--r--xml/details/genx/genx.c84
-rw-r--r--xml/details/genx/genx.h18
-rw-r--r--xml/serializer24
-rw-r--r--xml/serializer.cxx20
4 files changed, 142 insertions, 4 deletions
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, "</");
@@ -1804,7 +1876,11 @@ genxStatus genxEndElement(genxWriter w)
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 <b> 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<const char*> (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<size_t> (genxPrettyPrintSuspended (s_));
+ }
}