Author: rinrab
Date: Sun May 18 19:20:48 2025
New Revision: 1925686
URL: http://svn.apache.org/viewvc?rev=1925686&view=rev
Log:
On the 'xml-writer' branch: Implement the xml writer api.
* subversion/include/svn_xml.h
(svn_xml_writer_t,
(svn_xml_writer_create,
svn_xml_writer_close,
svn_xml_writer_flush,
svn_xml_write_open_tag,
svn_xml_write_open_tag_v,
svn_xml_write_open_tag_hash,
svn_xml_write_cdata_cstring,
svn_xml_write_cdata,
svn_xml_write_close_tag,
svn_xml_write_header): Declare symbols.
* subversion/libsvn_subr/xml_writer.c
(xml_stream_write,
xml_ensure_bytes,
xml_write_byte,
xml_write_bytes,
xml_write_cstring): Implement functions for writing data to the buffer.
(svn_xml_writer_create,
svn_xml_writer_close,
svn_xml_writer_flush,
svn_xml_write_open_tag,
svn_xml_write_open_tag_v,
svn_xml_write_open_tag_hash,
svn_xml_write_cdata_cstring,
svn_xml_write_cdata,
svn_xml_write_close_tag,
svn_xml_write_header): Implement symbols.
* subversion/tests/libsvn_subr/xml-test.c
(test_xml_writer,
test_xml_writer_always_flush): New tests.
(test_funcs): Run those tests.
Any kind of feedback will be much appreciated!!
Added:
subversion/branches/xml-writer/subversion/libsvn_subr/xml_writer.c (with props)
Modified:
subversion/branches/xml-writer/subversion/include/svn_xml.h
subversion/branches/xml-writer/subversion/tests/libsvn_subr/xml-test.c
Modified: subversion/branches/xml-writer/subversion/include/svn_xml.h
URL: http://svn.apache.org/viewvc/subversion/branches/xml-writer/subversion/include/svn_xml.h?rev=1925686&r1=1925685&r2=1925686&view=diff
==============================================================================
--- subversion/branches/xml-writer/subversion/include/svn_xml.h (original)
+++ subversion/branches/xml-writer/subversion/include/svn_xml.h Sun May 18 19:20:48 2025
@@ -399,6 +399,189 @@ svn_xml_make_close_tag(svn_stringbuf_t *
apr_pool_t *pool,
const char *tagname);
+/*---------------------------------------------------------------*/
+
+/** XML writer, writing XML tags to a generic stream.
+ *
+ * Summary
+ * ---
+ *
+ * The XML writer APIs provides functionality to write the XML tags to
+ * any writable stream, without having a need to manage a stringbuf,
+ * periodically write it to the output, and empty it then -- the XML
+ * writer implements this functionality.
+ *
+ * Usage
+ * ---
+ *
+ * 1. Create the writer using svn_xml_writer_create() before performing any
+ * writes.
+ *
+ * 2. During the lifetime of the XML writer, all the svn_xml_write_* functions
+ * can be safely invoked. Please note that they won't immediately write the
+ * data to the stream (more below), but you may force it using the
+ * svn_xml_writer_flush() function.
+ *
+ * 3. After the operation, the callers MUST close the writer using the
+ * svn_xml_writer_close() function. It will flush the remaining data in
+ * the buffer and close the ostream.
+ *
+ * Buffering
+ * ---
+ *
+ * The XML writer implements a temporary buffer, which will be filled with
+ * the content before it would have been flushed into the stream. This is
+ * used for optimization purposes, so we won't invoke the entire sequence
+ * of stream's write callbacks on each tag we want to write. The callers
+ * may use the svn_xml_writer_flush() function if they want to explicitly
+ * flush it to the stream. Otherwise, the writer will automatically flush
+ * the buffer as soon as it is about to exceed the limit.
+ *
+ * The buffering allows the callers to not care about how much tags do
+ * they want to write. If you are using it in a simple loop, no flushes are
+ * required. You may confidently rely to the automatic flush. However, if
+ * the code following after the write will wait for a long operation, for
+ * example, when the tag has been opened, but we need to do a request to a
+ * server, it's recommended to flush the buffer, so we won't have an opened
+ * tag partially written before the freeze.
+ *
+ * @since New in 1.15.
+ */
+
+typedef struct svn_xml_writer_t svn_xml_writer_t;
+
+/** Create an XML writer for writing to @a ostream. Sets @a writer with
+ * the result, allocated in @a result_pool.
+ *
+ * @a ostream will be closed with the writer, in the svn_xml_writer_close()
+ * function.
+ *
+ * The callers MUST close the writer via svn_xml_writer_close().
+ *
+ * @since New in 1.15.
+ */
+svn_error_t *
+svn_xml_writer_create(svn_xml_writer_t **writer,
+ svn_stream_t *ostream,
+ apr_pool_t *result_pool);
+
+/** Close @a xml_writer. This will also close the stream.
+ *
+ * @since New in 1.15.
+ */
+svn_error_t *
+svn_xml_writer_close(svn_xml_writer_t *xml_writer);
+
+/** Flush the buffer of @a xml_writer to the stream.
+ *
+ * @since New in 1.15.
+ */
+svn_error_t *
+svn_xml_writer_flush(svn_xml_writer_t *xml_writer);
+
+/** Write a new xml tag @a tagname to @a xml_writer.
+ *
+ * Take the tag's attributes from varargs, a SVN_VA_NULL-terminated list of
+ * alternating <tt>char *</tt> key and <tt>char *</tt> val. Do xml-escaping
+ * on each val.
+ *
+ * @a style is one of the enumerated styles in @c svn_xml_open_tag_style.
+ *
+ * Use @a scratch_pool for temporary allocations.
+ *
+ * This function is similar to svn_xml_make_open_tag(), but writes the
+ * result to an XML writer.
+ *
+ * @since New in 1.15.
+ */
+svn_error_t *
+svn_xml_write_open_tag(svn_xml_writer_t *xml_writer,
+ apr_pool_t *scratch_pool,
+ enum svn_xml_open_tag_style style,
+ const char *tagname, ...) SVN_NEEDS_SENTINEL_NULL;
+
+/** Like svn_xml_write_open_tag(), but takes a @c va_list instead of being
+ * variadic.
+ *
+ * This function is similar to svn_xml_make_open_tag_v(), but writes the
+ * result to an XML writer.
+ *
+ * @since New in 1.15.
+ */
+svn_error_t *
+svn_xml_write_open_tag_v(svn_xml_writer_t *xml_writer,
+ apr_pool_t *scratch_pool,
+ enum svn_xml_open_tag_style style,
+ const char *tagname, va_list ap);
+
+/** Like svn_xml_write_open_tag(), but takes a hash table of attributes
+ * (<tt>char *</tt> keys mapping to <tt>char *</tt> values).
+ *
+ * You might ask, why not just provide svn_xml_make_tag_atts()?
+ *
+ * The reason is that a hash table is the most natural interface to an
+ * attribute list; the fact that Expat uses <tt>char **</tt> atts instead is
+ * certainly a defensible implementation decision, but since we'd have
+ * to have special code to support such lists throughout Subversion
+ * anyway, we might as well write that code for the natural interface
+ * (hashes) and then convert in the few cases where conversion is
+ * needed. Someday it might even be nice to change expat-lite to work
+ * with apr hashes.
+ *
+ * See conversion functions svn_xml_make_att_hash() and
+ * svn_xml_make_att_hash_overlaying(). Callers should use those to
+ * convert Expat attr lists into hashes when necessary.
+ *
+ * This function is similar to svn_xml_make_open_tag_hash(), but writes the
+ * result to an XML writer.
+ *
+ * @since New in 1.15.
+ */
+svn_error_t *
+svn_xml_write_open_tag_hash(svn_xml_writer_t *xml_writer,
+ apr_pool_t *scratch_pool,
+ enum svn_xml_open_tag_style style,
+ const char *tagname, apr_hash_t *attributes);
+
+/** Writes and escapes cdata from a NULL-terminated string @a str
+ * to @a xml_writer.
+ *
+ * @since New in 1.15.
+ */
+svn_error_t *
+svn_xml_write_cdata_cstring(svn_xml_writer_t *xml_writer,
+ const char *str);
+
+/** Writes and escapes @a len cdata chars from @a data to @a xml_writer.
+ *
+ * @since New in 1.15.
+ */
+svn_error_t *
+svn_xml_write_cdata(svn_xml_writer_t *xml_writer,
+ const char *data, apr_size_t len);
+
+/** Write @a tagname close tag to @a xml_writer.
+ *
+ * @since New in 1.15.
+ */
+svn_error_t *
+svn_xml_write_close_tag(svn_xml_writer_t *xml_writer,
+ apr_pool_t *scratch_pool,
+ const char *tagname);
+
+/** Write an XML header to @a xml_writer.
+ *
+ * Fully-formed XML documents should start out with a header,
+ * something like <pre>
+ * \<?xml version="1.0" encoding="UTF-8"?\>
+ * </pre>
+ *
+ * @since New in 1.15.
+ */
+svn_error_t *
+svn_xml_write_header(svn_xml_writer_t *xml_writer,
+ const char *encoding,
+ apr_pool_t *scratch_pool);
#ifdef __cplusplus
}
Added: subversion/branches/xml-writer/subversion/libsvn_subr/xml_writer.c
URL: http://svn.apache.org/viewvc/subversion/branches/xml-writer/subversion/libsvn_subr/xml_writer.c?rev=1925686&view=auto
==============================================================================
--- subversion/branches/xml-writer/subversion/libsvn_subr/xml_writer.c (added)
+++ subversion/branches/xml-writer/subversion/libsvn_subr/xml_writer.c Sun May 18 19:20:48 2025
@@ -0,0 +1,369 @@
+/*
+ * xml_writer.c: svn_xml_writer_t implementation
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ */
+
+
+
+/*** Includes. ***/
+
+#include <assert.h>
+#include "svn_error.h"
+#include "svn_error_codes.h"
+#include "svn_io.h"
+#include "svn_string.h"
+#include "svn_xml.h"
+
+#include "svn_private_config.h"
+
+#define BUFFER_LENGTH 512
+
+
+/*** svn_xml_writer_t constructor and destructor ***/
+
+struct svn_xml_writer_t
+{
+ /* buffer and its offset */
+ char buffer[BUFFER_LENGTH];
+ apr_size_t offset;
+
+ /* an output stream, to write the XML to. */
+ svn_stream_t *ostream;
+
+ /* where this object is allocated, so we can free it easily */
+ apr_pool_t *pool;
+};
+
+svn_error_t *
+svn_xml_writer_create(svn_xml_writer_t **writer,
+ svn_stream_t *ostream,
+ apr_pool_t *result_pool)
+{
+ svn_xml_writer_t *result = apr_palloc(result_pool, sizeof(*result));
+
+ result->offset = 0;
+ result->ostream = ostream;
+ result->pool = result_pool;
+
+ *writer = result;
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_xml_writer_close(svn_xml_writer_t *writer)
+{
+ if (writer)
+ {
+ SVN_ERR(svn_xml_writer_flush(writer));
+ SVN_ERR(svn_stream_close(writer->ostream));
+ writer->ostream = NULL;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+/*** Buffering and writing routines ***/
+
+static svn_error_t *
+xml_stream_write(svn_xml_writer_t *writer, const char *data, apr_size_t len)
+{
+ apr_size_t write_len = len;
+
+ /* We're gonna bail on an incomplete write here only because we know
+ that this stream is really stdout, which should never be blocking
+ on us. */
+ SVN_ERR(svn_stream_write(writer->ostream, data, &write_len));
+ if (write_len != len)
+ return svn_error_create(SVN_ERR_STREAM_UNEXPECTED_EOF, NULL,
+ _("Error writing to stream"));
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_xml_writer_flush(svn_xml_writer_t *writer)
+{
+ if (writer->offset > 0)
+ {
+ SVN_ERR(xml_stream_write(writer, writer->buffer, writer->offset));
+ writer->offset = 0;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+xml_ensure_bytes(svn_xml_writer_t *writer, apr_size_t bytes)
+{
+ if (writer->offset + bytes > BUFFER_LENGTH)
+ SVN_ERR(svn_xml_writer_flush(writer));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+xml_write_byte(svn_xml_writer_t *writer, char b)
+{
+ SVN_ERR(xml_ensure_bytes(writer, 1));
+ writer->buffer[writer->offset++] = b;
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+xml_write_bytes(svn_xml_writer_t *writer, const char *data, apr_size_t len)
+{
+ if (len < BUFFER_LENGTH)
+ {
+ SVN_ERR(xml_ensure_bytes(writer, len));
+ memcpy(writer->buffer + writer->offset, data, len);
+ writer->offset += len;
+ }
+ else
+ {
+ SVN_ERR(svn_xml_writer_flush(writer));
+ SVN_ERR(xml_stream_write(writer, data, len));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+xml_write_cstring(svn_xml_writer_t *writer, const char *str)
+{
+ return svn_error_trace(xml_write_bytes(writer, str, strlen(str)));
+}
+
+svn_error_t *
+svn_xml_write_raw(svn_xml_writer_t *writer,
+ const char *data, apr_size_t len)
+{
+ return svn_error_trace(xml_write_bytes(writer, data, len));
+}
+
+/* XML Escaping */
+
+static svn_error_t *
+xml_write_escaped_attr(svn_xml_writer_t *xml_writer,
+ const char *data, apr_size_t len)
+{
+ const char *end = data + len;
+ const char *p = data, *q;
+
+ while (1)
+ {
+ /* Find a character which needs to be quoted and append bytes up
+ to that point. */
+ q = p;
+ while (q < end && *q != '&' && *q != '<' && *q != '>' && *q != '"' &&
+ *q != '\'' && *q != '\r' && *q != '\n' && *q != '\t')
+ q++;
+ SVN_ERR(xml_write_bytes(xml_writer, p, q - p));
+
+ /* We may already be a winner. */
+ if (q == end)
+ break;
+
+ /* Append the entity reference for the character. */
+ if (*q == '&')
+ SVN_ERR(xml_write_cstring(xml_writer, "&"));
+ else if (*q == '<')
+ SVN_ERR(xml_write_cstring(xml_writer, "<"));
+ else if (*q == '>')
+ SVN_ERR(xml_write_cstring(xml_writer, ">"));
+ else if (*q == '"')
+ SVN_ERR(xml_write_cstring(xml_writer, """));
+ else if (*q == '\'')
+ SVN_ERR(xml_write_cstring(xml_writer, "'"));
+ else if (*q == '\r')
+ SVN_ERR(xml_write_cstring(xml_writer, " "));
+ else if (*q == '\n')
+ SVN_ERR(xml_write_cstring(xml_writer, " "));
+ else if (*q == '\t')
+ SVN_ERR(xml_write_cstring(xml_writer, "	"));
+
+ p = q + 1;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_xml_write_cdata(svn_xml_writer_t *xml_writer,
+ const char *data, apr_size_t len)
+{
+ const char *end = data + len;
+ const char *p = data, *q;
+
+ while (1)
+ {
+ /* Find a character which needs to be quoted and append bytes up
+ to that point. Strictly speaking, '>' only needs to be
+ quoted if it follows "]]", but it's easier to quote it all
+ the time.
+
+ So, why are we escaping '\r' here? Well, according to the
+ XML spec, '\r\n' gets converted to '\n' during XML parsing.
+ Also, any '\r' not followed by '\n' is converted to '\n'. By
+ golly, if we say we want to escape a '\r', we want to make
+ sure it remains a '\r'! */
+ q = p;
+ while (q < end && *q != '&' && *q != '<' && *q != '>' && *q != '\r')
+ q++;
+ SVN_ERR(xml_write_bytes(xml_writer, p, q - p));
+
+ /* We may already be a winner. */
+ if (q == end)
+ break;
+
+ /* Append the entity reference for the character. */
+ if (*q == '&')
+ SVN_ERR(xml_write_cstring(xml_writer, "&"));
+ else if (*q == '<')
+ SVN_ERR(xml_write_cstring(xml_writer, "<"));
+ else if (*q == '>')
+ SVN_ERR(xml_write_cstring(xml_writer, ">"));
+ else if (*q == '\r')
+ SVN_ERR(xml_write_cstring(xml_writer, " "));
+
+ p = q + 1;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+
+/*** Writing an open tag ***/
+
+static svn_error_t *
+xml_write_attribute(svn_xml_writer_t *xml_writer,
+ const char *key, const char *val)
+{
+ SVN_ERR(xml_write_cstring(xml_writer, "\n "));
+ SVN_ERR(xml_write_cstring(xml_writer, key));
+ SVN_ERR(xml_write_cstring(xml_writer, "=\""));
+ SVN_ERR(xml_write_escaped_attr(xml_writer, val, strlen(val)));
+ SVN_ERR(xml_write_byte(xml_writer, '"'));
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_xml_write_open_tag_hash(svn_xml_writer_t *xml_writer,
+ apr_pool_t *scratch_pool,
+ enum svn_xml_open_tag_style style,
+ const char *tagname, apr_hash_t *attributes)
+{
+ apr_hash_index_t *hi;
+
+ SVN_ERR(xml_write_byte(xml_writer, '<'));
+ SVN_ERR(xml_write_cstring(xml_writer, tagname));
+
+ for (hi = apr_hash_first(scratch_pool, attributes);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ const void *key;
+ void *val;
+
+ apr_hash_this(hi, &key, NULL, &val);
+ assert(val != NULL);
+
+ SVN_ERR(xml_write_attribute(xml_writer, key, val));
+ }
+
+ if (style == svn_xml_self_closing)
+ SVN_ERR(xml_write_byte(xml_writer, '/'));
+ SVN_ERR(xml_write_byte(xml_writer, '>'));
+ if (style != svn_xml_protect_pcdata)
+ SVN_ERR(xml_write_byte(xml_writer, '\n'));
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_xml_write_open_tag_v(svn_xml_writer_t *xml_writer,
+ apr_pool_t *scratch_pool,
+ enum svn_xml_open_tag_style style,
+ const char *tagname,
+ va_list ap)
+{
+ apr_hash_t *ht = svn_xml_ap_to_hash(ap, scratch_pool);
+ return svn_error_trace(svn_xml_write_open_tag_hash(xml_writer, scratch_pool,
+ style, tagname, ht));
+}
+
+svn_error_t *
+svn_xml_write_open_tag(svn_xml_writer_t *xml_writer,
+ apr_pool_t *scratch_pool,
+ enum svn_xml_open_tag_style style,
+ const char *tagname,
+ ...)
+{
+ va_list ap;
+ svn_error_t *err;
+
+ va_start(ap, tagname);
+ err = svn_xml_write_open_tag_v(xml_writer, scratch_pool, style, tagname, ap);
+ va_end(ap);
+
+ return svn_error_trace(err);
+}
+
+
+
+svn_error_t *
+svn_xml_write_cdata_cstring(svn_xml_writer_t *xml_writer, const char *str)
+{
+ return svn_error_trace(svn_xml_write_cdata(xml_writer, str, strlen(str)));
+}
+
+/* close tag */
+
+svn_error_t *
+svn_xml_write_close_tag(svn_xml_writer_t *xml_writer,
+ apr_pool_t *scratch_pool,
+ const char *tagname)
+{
+ SVN_ERR(xml_write_cstring(xml_writer, "</"));
+ SVN_ERR(xml_write_cstring(xml_writer, tagname));
+ SVN_ERR(xml_write_cstring(xml_writer, ">\n"));
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_xml_write_header(svn_xml_writer_t *xml_writer,
+ const char *encoding,
+ apr_pool_t *scratch_pool)
+{
+ SVN_ERR(xml_write_cstring(xml_writer, "<?xml version=\"1.0\""));
+ if (encoding)
+ {
+ SVN_ERR(xml_write_cstring(xml_writer, " encoding=\""));
+ SVN_ERR(xml_write_cstring(xml_writer, encoding));
+ SVN_ERR(xml_write_cstring(xml_writer, "\""));
+ }
+ SVN_ERR(xml_write_cstring(xml_writer, "?>\n"));
+
+ return SVN_NO_ERROR;
+}
Propchange: subversion/branches/xml-writer/subversion/libsvn_subr/xml_writer.c
------------------------------------------------------------------------------
svn:eol-style = native
Modified: subversion/branches/xml-writer/subversion/tests/libsvn_subr/xml-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/xml-writer/subversion/tests/libsvn_subr/xml-test.c?rev=1925686&r1=1925685&r2=1925686&view=diff
==============================================================================
--- subversion/branches/xml-writer/subversion/tests/libsvn_subr/xml-test.c (original)
+++ subversion/branches/xml-writer/subversion/tests/libsvn_subr/xml-test.c Sun May 18 19:20:48 2025
@@ -396,6 +396,85 @@ test_xml_simple_attr_escape(apr_pool_t *
return SVN_NO_ERROR;
}
+static svn_error_t *
+test_xml_writer(apr_pool_t *pool)
+{
+ svn_stringbuf_t *str = svn_stringbuf_create_empty(pool);
+ svn_stream_t *stream = svn_stream_from_stringbuf(str, pool);
+ svn_xml_writer_t *xml_writer;
+
+ SVN_ERR(svn_xml_writer_create(&xml_writer, stream, pool));
+
+ SVN_ERR(svn_xml_write_open_tag(xml_writer, pool, svn_xml_normal, "root",
+ SVN_VA_NULL));
+
+ SVN_ERR(svn_xml_write_open_tag(xml_writer, pool, svn_xml_normal, "tag1",
+ SVN_VA_NULL));
+ SVN_ERR(svn_xml_write_cdata_cstring(xml_writer, "value"));
+ SVN_ERR(svn_xml_write_close_tag(xml_writer, pool, "tag1"));
+
+ SVN_ERR(svn_xml_write_open_tag(xml_writer, pool, svn_xml_normal, "tag2",
+ "a", "v", SVN_VA_NULL));
+ SVN_ERR(svn_xml_write_close_tag(xml_writer, pool, "tag2"));
+
+ SVN_ERR(svn_xml_write_close_tag(xml_writer, pool, "root"));
+
+ SVN_ERR(svn_xml_writer_close(xml_writer));
+
+ SVN_TEST_STRING_ASSERT(str->data, "<root>\n"
+ "<tag1>\n"
+ "value</tag1>\n"
+ "<tag2\n"
+ " a=\"v\">\n"
+ "</tag2>\n"
+ "</root>\n");
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+test_xml_writer_always_flush(apr_pool_t *pool)
+{
+ svn_stringbuf_t *str = svn_stringbuf_create_empty(pool);
+ svn_stream_t *stream = svn_stream_from_stringbuf(str, pool);
+ svn_xml_writer_t *xml_writer;
+
+ SVN_ERR(svn_xml_writer_create(&xml_writer, stream, pool));
+ SVN_ERR(svn_xml_writer_flush(xml_writer));
+
+ SVN_ERR(svn_xml_write_open_tag(xml_writer, pool, svn_xml_normal, "root",
+ SVN_VA_NULL));
+ SVN_ERR(svn_xml_writer_flush(xml_writer));
+
+ SVN_ERR(svn_xml_write_open_tag(xml_writer, pool, svn_xml_normal, "tag1",
+ SVN_VA_NULL));
+ SVN_ERR(svn_xml_writer_flush(xml_writer));
+ SVN_ERR(svn_xml_write_cdata_cstring(xml_writer, "value"));
+ SVN_ERR(svn_xml_writer_flush(xml_writer));
+ SVN_ERR(svn_xml_write_close_tag(xml_writer, pool, "tag1"));
+ SVN_ERR(svn_xml_writer_flush(xml_writer));
+ SVN_ERR(svn_xml_writer_flush(xml_writer));
+ SVN_ERR(svn_xml_writer_flush(xml_writer));
+
+ SVN_ERR(svn_xml_write_open_tag(xml_writer, pool, svn_xml_normal, "tag2",
+ "a", "v", SVN_VA_NULL));
+ SVN_ERR(svn_xml_writer_flush(xml_writer));
+ SVN_ERR(svn_xml_write_close_tag(xml_writer, pool, "tag2"));
+ SVN_ERR(svn_xml_write_close_tag(xml_writer, pool, "root"));
+
+ SVN_ERR(svn_xml_writer_close(xml_writer));
+
+ SVN_TEST_STRING_ASSERT(str->data, "<root>\n"
+ "<tag1>\n"
+ "value</tag1>\n"
+ "<tag2\n"
+ " a=\"v\">\n"
+ "</tag2>\n"
+ "</root>\n");
+
+ return SVN_NO_ERROR;
+}
+
/* The test table. */
static int max_threads = 1;
@@ -426,6 +505,10 @@ static struct svn_test_descriptor_t test
"simple XML cdata escaping test"),
SVN_TEST_PASS2(test_xml_simple_attr_escape,
"simple XML attribute escaping test"),
+ SVN_TEST_PASS2(test_xml_writer,
+ "test svn_xml_writer_t"),
+ SVN_TEST_PASS2(test_xml_writer_always_flush,
+ "test flush xml-writer after each action"),
SVN_TEST_NULL
};
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.