aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-08-11 23:47:47 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-08-11 23:47:47 +0200
commit503cd7a8cbb54719db115391de17ec265ea2b543 (patch)
tree0db5c25a13b30d90c34c2efc2b8591896bbe197d
parentd49c8876bc97a900c61bb053ecec9374be448014 (diff)
Add support for "checked" end_element(), end_attribute()
-rw-r--r--examples/xhtml/driver.cxx12
-rw-r--r--xml/details/genx/genx.c74
-rw-r--r--xml/details/genx/genx.h30
-rw-r--r--xml/serializer26
-rw-r--r--xml/serializer.cxx30
-rw-r--r--xml/serializer.ixx24
6 files changed, 169 insertions, 27 deletions
diff --git a/examples/xhtml/driver.cxx b/examples/xhtml/driver.cxx
index c298983..ff1d2a4 100644
--- a/examples/xhtml/driver.cxx
+++ b/examples/xhtml/driver.cxx
@@ -20,7 +20,7 @@ namespace xhtml
s.start_element (xmlns, "html");
s.namespace_decl (xmlns, "");
}
- inline void html_ (serializer& s) {s.end_element ();}
+ inline void html_ (serializer& s) {s.end_element (xmlns, "html");}
inline void _head (serializer& s)
{
@@ -29,16 +29,16 @@ namespace xhtml
s.attribute ("charset", "UTF-8");
s.end_element ();
}
- inline void head_ (serializer& s) {s.end_element ();}
+ inline void head_ (serializer& s) {s.end_element (xmlns, "head");}
inline void _title (serializer& s) {s.start_element (xmlns, "title");}
- inline void title_ (serializer& s) {s.end_element ();}
+ inline void title_ (serializer& s) {s.end_element (xmlns, "title");}
inline void _body (serializer& s) {s.start_element (xmlns, "body");}
- inline void body_ (serializer& s) {s.end_element ();}
+ inline void body_ (serializer& s) {s.end_element (xmlns, "body");}
inline void _p (serializer& s) {s.start_element (xmlns, "p");}
- inline void p_ (serializer& s) {s.end_element ();}
+ inline void p_ (serializer& s) {s.end_element (xmlns, "p");}
// "Inline" elements, i.e., those that are written without
// indentation.
@@ -50,7 +50,7 @@ namespace xhtml
}
inline void em_ (serializer& s)
{
- s.end_element ();
+ s.end_element (xmlns, "em");
s.resume_indentation ();
}
diff --git a/xml/details/genx/genx.c b/xml/details/genx/genx.c
index 387cc94..5c2cb1e 100644
--- a/xml/details/genx/genx.c
+++ b/xml/details/genx/genx.c
@@ -80,7 +80,7 @@ struct genxNamespace_rec
struct genxElement_rec
{
genxWriter writer;
- utf8 type;
+ utf8 name;
genxNamespace ns;
};
@@ -317,7 +317,7 @@ static genxNamespace findNamespace(plist * pl, constUtf8 uri)
return NULL;
}
-static genxElement findElement(plist * pl, constUtf8 xmlns, constUtf8 type)
+static genxElement findElement(plist * pl, constUtf8 xmlns, constUtf8 name)
{
size_t i;
genxElement * ee = (genxElement *) pl->pointers;
@@ -326,15 +326,15 @@ static genxElement findElement(plist * pl, constUtf8 xmlns, constUtf8 type)
{
if (xmlns == NULL)
{
- if (ee[i]->ns == NULL && strcmp((const char *) type,
- (const char *) ee[i]->type) == 0)
+ if (ee[i]->ns == NULL && strcmp((const char *) name,
+ (const char *) ee[i]->name) == 0)
return ee[i];
}
else
{
if (ee[i]->ns != NULL &&
strcmp((const char *) xmlns, (const char *) ee[i]->ns->name) == 0 &&
- strcmp((const char *) type, (const char *) ee[i]->type) == 0)
+ strcmp((const char *) name, (const char *) ee[i]->name) == 0)
return ee[i];
}
}
@@ -809,7 +809,7 @@ void genxDispose(genxWriter w)
for (i = 0; i < w->elements.count; i++)
{
- deallocate(w, ee[i]->type);
+ deallocate(w, ee[i]->name);
deallocate(w, ee[i]);
}
@@ -1066,20 +1066,20 @@ utf8 genxGetNamespacePrefix(genxNamespace ns)
* DeclareElement - see genx.h for details
*/
genxElement genxDeclareElement(genxWriter w,
- genxNamespace ns, constUtf8 type,
+ genxNamespace ns, constUtf8 name,
genxStatus * statusP)
{
genxElement old;
genxElement el;
- if ((w->status = checkNCName(w, type)) != GENX_SUCCESS)
+ if ((w->status = checkNCName(w, name)) != GENX_SUCCESS)
{
*statusP = w->status;
return NULL;
}
/* already declared? */
- old = findElement(&w->elements, (ns == NULL) ? NULL : ns->name, type);
+ old = findElement(&w->elements, (ns == NULL) ? NULL : ns->name, name);
if (old)
return old;
@@ -1091,7 +1091,7 @@ genxElement genxDeclareElement(genxWriter w,
el->writer = w;
el->ns = ns;
- if ((el->type = copy(w, type)) == NULL)
+ if ((el->name = copy(w, name)) == NULL)
{
w->status = *statusP = GENX_ALLOC_FAILED;
return NULL;
@@ -1378,7 +1378,7 @@ static genxStatus writeStartTag(genxWriter w, Boolean close)
SendCheck(w, e->ns->declaration->name + STRLEN_XMLNS_COLON);
SendCheck(w, ":");
}
- SendCheck(w, e->type);
+ SendCheck(w, e->name);
/* If we are canonicalizing, then write sorted attributes. Otherwise
write them in the order specified. */
@@ -1780,6 +1780,22 @@ genxStatus genxStartAttribute(genxAttribute a)
return GENX_SUCCESS;
}
+genxStatus genxGetCurrentAttribute (genxWriter w,
+ constUtf8* xmlns, constUtf8* name)
+{
+ genxAttribute a;
+
+ if (w->sequence != SEQUENCE_START_ATTR)
+ return w->status = GENX_SEQUENCE_ERROR;
+
+ a = w->nowStartingAttr;
+
+ *xmlns = a->ns ? a->ns->name : NULL;
+ *name = a->name;
+
+ return GENX_SUCCESS;
+}
+
genxStatus genxEndAttribute(genxWriter w)
{
genxAttribute a;
@@ -1813,6 +1829,36 @@ genxStatus genxEndAttribute(genxWriter w)
return GENX_SUCCESS;
}
+genxStatus genxGetCurrentElement (genxWriter w,
+ constUtf8* xmlns, constUtf8* name)
+{
+ int i;
+ genxElement e;
+
+ switch (w->sequence)
+ {
+ case SEQUENCE_START_TAG:
+ case SEQUENCE_ATTRIBUTES:
+ e = w->nowStarting;
+ break;
+ case SEQUENCE_CONTENT:
+ /* Find the element. The same code as in EndElement() below. */
+ for (i = (int) (w->stack.count) - 1;
+ w->stack.pointers[i] != NULL;
+ i -= 2)
+ ;
+ e = (genxElement) w->stack.pointers[--i];
+ break;
+ default:
+ return w->status = GENX_SEQUENCE_ERROR;
+ }
+
+ *xmlns = e->ns ? e->ns->name : NULL;
+ *name = e->name;
+
+ return GENX_SUCCESS;
+}
+
genxStatus genxEndElement(genxWriter w)
{
int i;
@@ -1872,7 +1918,7 @@ genxStatus genxEndElement(genxWriter w)
SendCheck(w, e->ns->declaration->name + STRLEN_XMLNS_COLON);
SendCheck(w, ":");
}
- SendCheck(w, e->type);
+ SendCheck(w, e->name);
SendCheck(w, ">");
}
@@ -2379,7 +2425,7 @@ genxStatus genxPI(genxWriter w, constUtf8 target, constUtf8 text)
* Literal versions of the writing routines
*/
genxStatus genxStartElementLiteral(genxWriter w,
- constUtf8 xmlns, constUtf8 type)
+ constUtf8 xmlns, constUtf8 name)
{
genxNamespace ns = NULL;
genxElement e;
@@ -2390,7 +2436,7 @@ genxStatus genxStartElementLiteral(genxWriter w,
if (ns == NULL || w->status != GENX_SUCCESS)
return w->status;
}
- e = genxDeclareElement(w, ns, type, &w->status);
+ e = genxDeclareElement(w, ns, name, &w->status);
if (e == NULL || w->status != GENX_SUCCESS)
return w->status;
diff --git a/xml/details/genx/genx.h b/xml/details/genx/genx.h
index 89f0637..c727cd9 100644
--- a/xml/details/genx/genx.h
+++ b/xml/details/genx/genx.h
@@ -180,7 +180,7 @@ genxNamespace genxDeclareNamespace(genxWriter w,
* If something failed, returns NULL and sets the status code via statusP
*/
genxElement genxDeclareElement(genxWriter w,
- genxNamespace ns, constUtf8 type,
+ genxNamespace ns, constUtf8 name,
genxStatus * statusP);
/*
@@ -210,7 +210,7 @@ typedef struct
genxStatus genxStartDocSender(genxWriter w, genxSender * sender);
/*
- * End a document. Calls "flush"
+ * End a document. Calls "flush".
*/
genxStatus genxEndDocument(genxWriter w);
@@ -249,7 +249,7 @@ genxStatus genxPI(genxWriter w, constUtf8 target, constUtf8 text);
* Start an element
*/
genxStatus genxStartElementLiteral(genxWriter w,
- constUtf8 xmlns, constUtf8 type);
+ constUtf8 xmlns, constUtf8 name);
/*
* Start a predeclared element
@@ -258,26 +258,42 @@ genxStatus genxStartElementLiteral(genxWriter w,
genxStatus genxStartElement(genxElement e);
/*
+ * Get current element. The returned values are valid until this
+ * element ceases to be current (i.e., EndElement() is called).
+ * If the element is unqualified, then xmlns is set to NULL.
+ */
+genxStatus genxGetCurrentElement (genxWriter w,
+ constUtf8* xmlns, constUtf8* name);
+
+/*
* Write an attribute
*/
genxStatus genxAddAttributeLiteral(genxWriter w, constUtf8 xmlns,
constUtf8 name, constUtf8 value);
/*
+ * Write a predeclared attribute
+ */
+genxStatus genxAddAttribute(genxAttribute a, constUtf8 value);
+
+/*
* Start an attribute
*/
genxStatus genxStartAttributeLiteral(genxWriter w,
constUtf8 xmlns, constUtf8 name);
/*
- * Write a predeclared attribute
+ * Start a predeclared attribute
*/
-genxStatus genxAddAttribute(genxAttribute a, constUtf8 value);
+genxStatus genxStartAttribute(genxAttribute a);
/*
- * Start a predeclared attribute
+ * Get current attribute. The returned values are valid until this
+ * attribute ceases to be current (i.e., EndAttribute() is called).
+ * If the attribute is unqualified, then xmlns is set to NULL.
*/
-genxStatus genxStartAttribute(genxAttribute a);
+genxStatus genxGetCurrentAttribute (genxWriter w,
+ constUtf8* xmlns, constUtf8* name);
/*
* End an attribute
diff --git a/xml/serializer b/xml/serializer
index eb592df..0624634 100644
--- a/xml/serializer
+++ b/xml/serializer
@@ -97,6 +97,19 @@ namespace xml
void
end_element ();
+ // "Checked" end element. That is, it checks that the element
+ // you think you are ending matches the current one.
+ //
+ void
+ end_element (const qname_type& qname);
+
+ void
+ end_element (const std::string& name);
+
+ void
+ end_element (const std::string& ns, const std::string& name);
+
+
// Helpers for serializing elements with simple content. The first two
// functions assume that start_element() has already been called. The
// other two serialize the complete element, from start to end.
@@ -147,6 +160,19 @@ namespace xml
void
end_attribute ();
+ // "Checked" end attribute. That is, it checks that the attribute
+ // you think you are ending matches the current one.
+ //
+ void
+ end_attribute (const qname_type& qname);
+
+ void
+ end_attribute (const std::string& name);
+
+ void
+ end_attribute (const std::string& ns, const std::string& name);
+
+
void
attribute (const qname_type& qname, const std::string& value);
diff --git a/xml/serializer.cxx b/xml/serializer.cxx
index 5ed5c5e..df31b09 100644
--- a/xml/serializer.cxx
+++ b/xml/serializer.cxx
@@ -173,6 +173,21 @@ namespace xml
}
void serializer::
+ end_element (const string& ns, const string& name)
+ {
+ constUtf8 cns, cn;
+ genxStatus e;
+ if ((e = genxGetCurrentElement (s_, &cns, &cn)) ||
+ reinterpret_cast<const char*> (cn) != name ||
+ (cns == 0 ? !ns.empty () : reinterpret_cast<const char*> (cns) != ns))
+ {
+ handle_error (e != GENX_SUCCESS ? e : GENX_SEQUENCE_ERROR);
+ }
+
+ end_element ();
+ }
+
+ void serializer::
element (const string& ns, const string& n, const string& v)
{
start_element (ns, n);
@@ -197,6 +212,21 @@ namespace xml
}
void serializer::
+ end_attribute (const string& ns, const string& name)
+ {
+ constUtf8 cns, cn;
+ genxStatus e;
+ if ((e = genxGetCurrentAttribute (s_, &cns, &cn)) ||
+ reinterpret_cast<const char*> (cn) != name ||
+ (cns == 0 ? !ns.empty () : reinterpret_cast<const char*> (cns) != ns))
+ {
+ handle_error (e != GENX_SUCCESS ? e : GENX_SEQUENCE_ERROR);
+ }
+
+ end_attribute ();
+ }
+
+ void serializer::
attribute (const string& ns,
const string& name,
const string& value)
diff --git a/xml/serializer.ixx b/xml/serializer.ixx
index 5cff976..465fede 100644
--- a/xml/serializer.ixx
+++ b/xml/serializer.ixx
@@ -19,6 +19,18 @@ namespace xml
}
inline void serializer::
+ end_element (const qname_type& qname)
+ {
+ end_element (qname.namespace_ (), qname.name ());
+ }
+
+ inline void serializer::
+ end_element (const std::string& name)
+ {
+ end_element (std::string (), name);
+ }
+
+ inline void serializer::
element (const std::string& v)
{
if (!v.empty ())
@@ -80,6 +92,18 @@ namespace xml
}
inline void serializer::
+ end_attribute (const qname_type& qname)
+ {
+ end_attribute (qname.namespace_ (), qname.name ());
+ }
+
+ inline void serializer::
+ end_attribute (const std::string& name)
+ {
+ end_attribute (std::string (), name);
+ }
+
+ inline void serializer::
attribute (const qname_type& qname, const std::string& value)
{
attribute (qname.namespace_ (), qname.name (), value);