From 503cd7a8cbb54719db115391de17ec265ea2b543 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 11 Aug 2015 23:47:47 +0200 Subject: Add support for "checked" end_element(), end_attribute() --- examples/xhtml/driver.cxx | 12 ++++---- xml/details/genx/genx.c | 74 ++++++++++++++++++++++++++++++++++++++--------- xml/details/genx/genx.h | 30 ++++++++++++++----- xml/serializer | 26 +++++++++++++++++ xml/serializer.cxx | 30 +++++++++++++++++++ xml/serializer.ixx | 24 +++++++++++++++ 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 (cn) != name || + (cns == 0 ? !ns.empty () : reinterpret_cast (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 (cn) != name || + (cns == 0 ? !ns.empty () : reinterpret_cast (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); -- cgit v1.1