5
gSOAP DOM implementation
7
gSOAP XML Web services tools
8
Copyright (C) 2001-2004, Robert van Engelen, Genivia, Inc. All Rights Reserved.
10
--------------------------------------------------------------------------------
12
This software is released under one of the following three licenses:
13
GPL, the gSOAP public license, or Genivia's license for commercial use.
15
--------------------------------------------------------------------------------
18
The contents of this file are subject to the gSOAP Public License Version 1.3
19
(the "License"); you may not use this file except in compliance with the
20
License. You may obtain a copy of the License at
21
http://www.cs.fsu.edu/~engelen/soaplicense.html
22
Software distributed under the License is distributed on an "AS IS" basis,
23
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
24
for the specific language governing rights and limitations under the License.
26
The Initial Developer of the Original Code is Robert A. van Engelen.
27
Copyright (C) 2000-2004 Robert A. van Engelen, Genivia inc. All Rights Reserved.
28
--------------------------------------------------------------------------------
31
This program is free software; you can redistribute it and/or modify it under
32
the terms of the GNU General Public License as published by the Free Software
33
Foundation; either version 2 of the License, or (at your option) any later
36
This program is distributed in the hope that it will be useful, but WITHOUT ANY
37
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
38
PARTICULAR PURPOSE. See the GNU General Public License for more details.
40
You should have received a copy of the GNU General Public License along with
41
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
42
Place, Suite 330, Boston, MA 02111-1307 USA
44
Author contact information:
45
engelen@genivia.com / engelen@acm.org
46
--------------------------------------------------------------------------------
47
A commercial use license is available from Genivia, Inc., contact@genivia.com
48
--------------------------------------------------------------------------------
50
This level-2 DOM parser features automatic XML namespace handling and
51
allows mixing with gSOAP's data type (de)serializers.
53
DOM element nodes and attribute nodes can have an optional namespace
54
names. The namespace prefix and name bindings (xmlns in XML) are
55
automatically resolved.
57
The DOM elements can be used anywhere within a C/C++ data structure and
58
also as the arguments to a service method. For example:
59
struct SOAP_ENV__Header
60
{ xsd__anyType *authentication;
62
int ns__test(xsd__anyType in, xsd__anyType *out);
63
which defines a custom SOAP Header with an authentication element
67
*elts optional child elements (list of DOM nodes)
68
*atts optional attributes of element node
69
const char *nstr element namespace name (URI)
70
char *name element name with optional ns: prefix
71
char *data optional element data (see comment below)
72
wchar_t *wide optional element data (see comment below)
73
int type optional type (SOAP_TYPE_X as defined in soapH.h)
74
void *node and optional element pointer to C/C++ data type
77
The namespace name (URI) parsing is smart and fills the 'nstr' field
78
with the namespace URIs. The algorithm checks the names in the nsmap
79
table first. After parsing, the 'nstr' namespace strings will point to
80
the nsmap table contents in case the names (URIs) match a table entry.
81
Otherwise, the names are dynamically allocated. This enables quick
82
pointer-based checks on the DOM node's namespace names by comparing the
83
pointer to the namespace table entries 'namespaces[i].ns'.
85
Character data parsing:
86
The parser fills the 'wide' string fields of the DOM nodes only (the
87
'wide' fields contain Unicode XML cdata), unless the input-mode flag
88
SOAP_C_UTFSTRING or SOAP_C_MBSTRING is set using soap_init2() or
89
soap_set_imode(). In that case the 'data' fields are set with UTF8
90
contents or multibyte character strings.
92
The following input-mode flags (set with soap_set_imode()) control the
93
parsing of C/C++ data types (stored in the 'node' and 'type' fields):
95
default: only elements with an 'id' attribute are deserialized
96
as C/C++ data types (when a deserializer is available)
97
SOAP_DOM_TREE: never deserialize C/C++ types (produces DOM tree)
98
SOAP_DOM_NODE: always deserialize C/C++ types (when a deserializer is
99
available and the xsi:type attribute is present in the
100
XML node or the XML element tag matches the type name)
102
The following output-mode flag (set with soap_set_omode()) controls the
103
serialization of XML:
105
SOAP_XML_CANONICAL: serialize XML in canonical form
107
The entire deserialized DOM is freed with
108
soap_destroy(DOM.soap);
111
Examples (XML parsing and generation):
113
struct soap *soap = soap_new();
114
xsd__anyType dom(soap); // need a soap struct to parse XML using '>>'
115
cin >> dom; // parse XML
118
soap_destroy(soap); // delete DOM
119
soap_end(soap); // delete data
120
soap_done(soap); // finalize
123
struct soap *soap = soap_new();
124
xsd__anyType dom(soap, ...); // populate the DOM
125
cout << dom; // print
128
soap_destroy(soap); // clean up objects
129
soap_end(soap); // clean up
130
soap_done(soap); // finalize
133
To retain the DOM but remove all other data, use:
140
To use a DOM in your Web service application, add to the gSOAP header
141
file that defines your service:
143
Then use the xsd__anyType to refer to the DOM in your data structures.
145
Link the application with dom.o
148
Reused the gSOAP struct soap id hash table for handling namespace
149
bindings when transmitting DOMs
152
Renamed __type to type (correction)
153
dom.c, dom++.cpp, and dom.cpp are equivalent
154
Renamed SOAP_XML_TREE to SOAP_DOM_TREE
155
Renamed SOAP_XML_GRAPH to SOAP_DOM_NODE
157
TODO: Improve mixed content handling
160
#include "stdsoap2.h"
162
SOAP_FMAC3 void SOAP_FMAC4 soap_serialize_xsd__anyType(struct soap*, struct soap_dom_element const*);
163
SOAP_FMAC1 void SOAP_FMAC2 soap_mark_xsd__anyType(struct soap*, const struct soap_dom_element *);
164
SOAP_FMAC1 void SOAP_FMAC2 soap_default_xsd__anyType(struct soap*, struct soap_dom_element *);
165
SOAP_FMAC3 int SOAP_FMAC4 soap_put_xsd__anyType(struct soap*, const struct soap_dom_element *, const char*, const char*);
166
SOAP_FMAC1 int SOAP_FMAC2 soap_out_xsd__anyType(struct soap*, const char*, int, const struct soap_dom_element *, const char*);
167
SOAP_FMAC3 struct soap_dom_element * SOAP_FMAC4 soap_get_xsd__anyType(struct soap*, struct soap_dom_element *, const char*, const char*);
168
SOAP_FMAC1 struct soap_dom_element * SOAP_FMAC2 soap_in_xsd__anyType(struct soap*, const char*, struct soap_dom_element *, const char*);
170
SOAP_FMAC3 void SOAP_FMAC4 soap_markelement(struct soap*, const void*, int);
171
SOAP_FMAC3 int SOAP_FMAC4 soap_putelement(struct soap*, const void*, const char*, int, int);
172
SOAP_FMAC3 void *SOAP_FMAC4 soap_getelement(struct soap*, int*);
174
/* format string for generating DOM namespace prefixes (<= 16 chars total) */
175
#define SOAP_DOMID_FORMAT "SOAP-DOM%lu"
177
/* namespace name (URI) lookup and store routines */
178
static struct soap_ilist *soap_lookup_ns(struct soap*, const char*);
179
static struct soap_ilist *soap_enter_ns(struct soap*, const char*, const char*);
182
** DOM custom (de)serializers
188
soap_mark_xsd__anyType(struct soap *soap, const struct soap_dom_element *node)
190
{ if (node->type && node->node)
191
soap_markelement(soap, node->node, node->type);
192
else if (!node->data && !node->wide)
193
{ struct soap_dom_element *elt;
194
for (elt = node->elts; elt; elt = elt->next)
195
soap_mark_xsd__anyType(soap, elt);
203
soap_default_xsd__anyType(struct soap *soap, struct soap_dom_element *node)
217
static int element(struct soap *soap, const char *name)
218
{ short part = soap->part;
219
soap->part = SOAP_IN_ENVELOPE; /* use this to avoid SOAP encoding and literal encoding issues */
220
soap_element(soap, name, 0, NULL);
225
static int out_element(struct soap *soap, const struct soap_dom_element *node, const char *prefix, const char *name, const char *nstr)
227
{ if (node->type && node->node)
228
return soap_putelement(soap, node->node, name, 0, node->type);
229
return element(soap, name);
231
if (node->type && node->node)
232
{ char *s = (char*)malloc(strlen(prefix) + strlen(name) + 2);
234
return soap->error = SOAP_EOM;
235
sprintf(s, "%s:%s", prefix, name);
236
soap_putelement(soap, node->node, s, 0, node->type);
239
else if (strlen(prefix) + strlen(name) < sizeof(soap->msgbuf))
240
{ sprintf(soap->msgbuf, "%s:%s", prefix, name);
241
if (element(soap, soap->msgbuf))
244
{ sprintf(soap->msgbuf, "xmlns:%s", prefix);
245
soap_attribute(soap, soap->msgbuf, nstr);
249
{ char *s = (char*)malloc(strlen(prefix) + strlen(name) + 2);
251
return soap->error = SOAP_EOM;
252
sprintf(s, "%s:%s", prefix, name);
253
if (element(soap, s))
256
{ sprintf(s, "xmlns:%s", prefix);
257
soap_attribute(soap, s, nstr);
264
static int out_attribute(struct soap *soap, const char *prefix, const char *name, const char *data)
266
return soap_attribute(soap, name, data);
267
if (strlen(prefix) + strlen(name) < sizeof(soap->msgbuf))
268
{ sprintf(soap->msgbuf, "%s:%s", prefix, name);
269
soap_attribute(soap, soap->msgbuf, data);
272
{ char *s = (char*)malloc(strlen(prefix) + strlen(name) + 2);
274
return soap->error = SOAP_EOM;
275
sprintf(s, "%s:%s", prefix, name);
276
soap_attribute(soap, s, data);
285
soap_out_xsd__anyType(struct soap *soap, const char *tag, int id, const struct soap_dom_element *node, const char *type)
287
{ struct soap_dom_element *elt;
288
struct soap_dom_attribute *att;
289
register struct soap_ilist *p = NULL, *q;
290
struct Namespace *ns = NULL;
291
const char *prefix; /* namespace prefix, if namespace is present */
297
if ((prefix = strchr(tag, ':')))
298
{ colon = prefix - tag + 1;
299
if (colon > sizeof(soap->tag))
300
colon = sizeof(soap->tag);
303
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "DOM node '%s'\n", tag));
305
{ if ((p = soap_lookup_ns(soap, node->nstr)))
308
if (out_element(soap, node, prefix, tag + colon, NULL))
312
{ strncpy(soap->tag, tag, colon - 1);
313
soap->tag[colon - 1] = '\0';
314
if (!(p = soap_enter_ns(soap, soap->tag, node->nstr)))
315
return soap->error = SOAP_EOM;
317
if (out_element(soap, node, prefix, tag + colon, node->nstr))
321
{ for (ns = soap->local_namespaces; ns && ns->id; ns++)
322
if (ns->ns == node->nstr || !strcmp(ns->ns, node->nstr))
323
{ /* if (soap->encodingStyle || ns == soap->local_namespaces) */
325
if (out_element(soap, node, ns->id, tag + colon, NULL))
330
{ sprintf(soap->tag, SOAP_DOMID_FORMAT, soap->idnum++);
331
if (!(p = soap_enter_ns(soap, soap->tag, node->nstr)))
332
return soap->error = SOAP_EOM;
334
if (out_element(soap, node, prefix, tag + colon, node->nstr))
339
else if (out_element(soap, node, NULL, tag + colon, NULL))
341
if (node->type && node->node)
343
for (att = node->atts; att; att = att->next)
346
{ if ((att->nstr == node->nstr || (node->nstr && !strcmp(att->nstr, node->nstr))) && prefix)
347
{ if (out_attribute(soap, prefix, att->name, att->data))
350
else if ((q = soap_lookup_ns(soap, att->nstr)))
351
{ if (out_attribute(soap, q->id, att->name, att->data))
355
{ for (ns = soap->local_namespaces; ns && ns->id; ns++)
356
{ if (ns->ns == att->nstr || !strcmp(ns->ns, att->nstr))
357
{ if (out_attribute(soap, ns->id, att->name, att->data))
363
{ sprintf(soap->msgbuf, "xmlns:"SOAP_DOMID_FORMAT, soap->idnum++);
364
if (soap_attribute(soap, soap->msgbuf, att->nstr))
366
strcat(soap->msgbuf, ":");
367
strcat(soap->msgbuf, att->name);
368
if (soap_attribute(soap, soap->msgbuf + 6, att->data))
373
else if (soap_attribute(soap, att->name, att->data))
377
if (soap_element_start_end_out(soap, NULL))
379
if (node->data || node->wide || node->elts)
381
{ if (soap_string_out(soap, node->data, 0))
385
{ if (soap_wstring_out(soap, node->wide, 0))
389
{ for (elt = node->elts; elt; elt = elt->next)
390
if (soap_out_xsd__anyType(soap, tag, 0, elt, NULL))
394
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "End of DOM node '%s'\n", tag + colon));
395
if (soap_send_raw(soap, "</", 2))
398
if (soap_send(soap, prefix) || soap_send_raw(soap, ":", 1))
400
if (soap_send(soap, tag + colon) || soap_send_raw(soap, ">", 1))
403
p->level = 0; /* xmlns binding is out of scope */
409
struct soap_dom_element *
411
soap_in_xsd__anyType(struct soap *soap, const char *tag, struct soap_dom_element *node, const char *type)
412
{ register struct soap_attribute *tp;
413
register struct soap_dom_attribute **att;
414
register struct soap_nlist *np;
416
if (soap_peek_element(soap))
419
if (!(node = (struct soap_dom_element*)soap_malloc(soap, sizeof(struct soap_dom_element))))
420
{ soap->error = SOAP_EOM;
423
soap_default_xsd__anyType(soap, node);
424
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "DOM node %s\n", soap->tag));
426
if (!(s = strchr(soap->tag, ':')))
427
{ while (np && *np->id) /* find default namespace, if present */
432
{ while (np && (strncmp(np->id, soap->tag, s - soap->tag) || np->id[s - soap->tag]))
436
{ soap->error = SOAP_NAMESPACE;
441
{ if (np->index >= 0)
442
node->nstr = soap->namespaces[np->index].ns;
444
node->nstr = soap_strdup(soap, np->ns);
445
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "DOM node namespace='%s'\n", node->nstr?node->nstr:""));
447
node->name = soap_strdup(soap, soap->tag);
448
if ((soap->mode & SOAP_DOM_NODE) || (!(soap->mode & SOAP_DOM_TREE) && *soap->id))
449
{ if ((node->node = soap_getelement(soap, &node->type)))
450
{ DBGLOG(TEST, SOAP_MESSAGE(fdebug, "DOM node contains type %d from xsi:type\n", node->type));
453
if (soap->error == SOAP_TAG_MISMATCH)
454
soap->error = SOAP_OK;
459
for (tp = soap->attributes; tp; tp = tp->next)
462
if (!(s = strchr(tp->name, ':')))
463
{ while (np && *np->id) /* find default namespace, if present */
468
{ while (np && (strncmp(np->id, tp->name, s - tp->name) || np->id[s - tp->name]))
472
{ soap->error = SOAP_NAMESPACE;
476
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "DOM node attribute='%s'\n", tp->name));
477
*att = (struct soap_dom_attribute*)soap_malloc(soap, sizeof(struct soap_dom_attribute));
479
{ soap->error = SOAP_EOM;
485
{ if (np->index >= 0)
486
(*att)->nstr = soap->namespaces[np->index].ns;
488
(*att)->nstr = soap_strdup(soap, np->ns);
489
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "DOM attribute namespace='%s'\n", (*att)->nstr?(*att)->nstr:""));
491
(*att)->name = soap_strdup(soap, s);
492
if (tp->visible == 2)
493
(*att)->data = soap_strdup(soap, tp->value);
500
soap_element_begin_in(soap, NULL, 1);
501
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "DOM node '%s' accepted\n", node->name));
504
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "DOM node '%s' has content\n", node->name));
505
do c = soap_getchar(soap);
506
while (c > 0 && c <= 32);
508
{ soap->error = SOAP_EOF;
513
{ struct soap_dom_element **elt;
514
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "DOM node '%s' has subelements\n", node->name));
517
{ if (!(*elt = soap_in_xsd__anyType(soap, NULL, NULL, NULL)))
518
{ if (soap->error == SOAP_NO_TAG)
519
soap->error = SOAP_OK;
529
{ DBGLOG(TEST, SOAP_MESSAGE(fdebug, "DOM node '%s' has cdata\n", node->name));
530
if ((soap->mode & SOAP_C_UTFSTRING) || (soap->mode & SOAP_C_MBSTRING))
531
{ if (!(node->data = soap_string_in(soap, 1, -1, -1)))
534
else if (!(node->wide = soap_wstring_in(soap, 1, -1, -1)))
537
if (soap_element_end_in(soap, node->name))
539
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "End of DOM node '%s'\n", node->name));
545
** Namespace lookup/store routines
548
static struct soap_ilist *
549
soap_lookup_ns(struct soap *soap, const char *nstr)
550
{ register struct soap_ilist *ip;
551
for (ip = soap->iht[soap_hash(nstr)]; ip; ip = ip->next)
552
if (!strcmp((char*)ip->ptr, nstr) && ip->level)
557
static struct soap_ilist *
558
soap_enter_ns(struct soap *soap, const char *prefix, const char *nstr)
560
register struct soap_ilist *ip;
561
for (ip = soap->iht[soap_hash(nstr)]; ip; ip = ip->next)
562
{ if (!strcmp((char*)ip->ptr, nstr) && !ip->level)
563
{ strcpy(ip->id, prefix);
568
ip = (struct soap_ilist*)malloc(sizeof(struct soap_ilist) + strlen(nstr) + SOAP_TAGLEN);
570
{ h = soap_hash(nstr);
571
strcpy(ip->id, prefix);
572
ip->ptr = ip->id + SOAP_TAGLEN;
573
strcpy((char*)ip->ptr, nstr);
574
ip->next = soap->iht[h];
586
** Class soap_dom_element
589
soap_dom_element::soap_dom_element()
603
soap_dom_element::soap_dom_element(struct soap *soap)
617
soap_dom_element::soap_dom_element(struct soap *soap, const char *nstr, const char *name)
623
this->nstr = soap_strdup(soap, nstr);
624
this->name = soap_strdup(soap, name);
631
soap_dom_element::soap_dom_element(struct soap *soap, const char *nstr, const char *name, const char *data)
635
this->nstr = soap_strdup(soap, nstr);
636
this->name = soap_strdup(soap, name);
637
this->data = soap_strdup(soap, data);
645
soap_dom_element::soap_dom_element(struct soap *soap, const char *nstr, const char *name, void *node, int type)
649
this->nstr = soap_strdup(soap, nstr);
650
this->name = soap_strdup(soap, name);
659
soap_dom_element::~soap_dom_element()
662
soap_dom_element &soap_dom_element::set(const char *nstr, const char *name)
663
{ this->nstr = soap_strdup(soap, nstr);
664
this->name = soap_strdup(soap, name);
668
soap_dom_element &soap_dom_element::set(const char *data)
669
{ this->data = soap_strdup(soap, data);
673
soap_dom_element &soap_dom_element::set(void *node, int type)
679
soap_dom_element &soap_dom_element::add(struct soap_dom_element *elt)
681
for (struct soap_dom_element *e = elts; e; e = e->next)
690
soap_dom_element &soap_dom_element::add(struct soap_dom_element &elt)
694
soap_dom_element &soap_dom_element::add(struct soap_dom_attribute *att)
695
{ for (struct soap_dom_attribute *a = atts; a; a = a->next)
704
soap_dom_element &soap_dom_element::add(struct soap_dom_attribute &att)
708
soap_dom_iterator soap_dom_element::begin()
709
{ soap_dom_iterator iter(this);
713
soap_dom_iterator soap_dom_element::end()
714
{ soap_dom_iterator iter(NULL);
718
soap_dom_iterator soap_dom_element::find(const char *nstr, const char *name)
719
{ soap_dom_iterator iter(this);
722
if (name && soap_tag_cmp(this->name, name))
724
if (nstr && this->nstr && soap_tag_cmp(this->nstr, nstr))
729
soap_dom_iterator soap_dom_element::find(int type)
730
{ soap_dom_iterator iter(this);
732
if (this->type != type)
737
void soap_dom_element::unlink()
738
{ soap_unlink(soap, this);
739
soap_unlink(soap, nstr);
740
soap_unlink(soap, name);
741
soap_unlink(soap, data);
742
soap_unlink(soap, wide);
754
** Class soap_dom_attribute
757
soap_dom_attribute::soap_dom_attribute()
761
soap_dom_attribute::soap_dom_attribute(struct soap *soap)
770
soap_dom_attribute::soap_dom_attribute(struct soap *soap, const char *nstr, const char *name, const char *data)
773
this->nstr = soap_strdup(soap, nstr);
774
this->name = soap_strdup(soap, name);
775
this->data = soap_strdup(soap, data);
779
soap_dom_attribute::~soap_dom_attribute()
782
void soap_dom_attribute::unlink()
783
{ soap_unlink(soap, this);
784
soap_unlink(soap, nstr);
785
soap_unlink(soap, name);
786
soap_unlink(soap, data);
787
soap_unlink(soap, wide);
793
** Class soap_dom_iterator
796
soap_dom_iterator::soap_dom_iterator()
803
soap_dom_iterator::soap_dom_iterator(struct soap_dom_element *elt)
810
soap_dom_iterator::~soap_dom_iterator()
813
bool soap_dom_iterator::operator==(const soap_dom_iterator &iter) const
814
{ return this->elt == iter.elt;
817
bool soap_dom_iterator::operator!=(const soap_dom_iterator &iter) const
818
{ return this->elt != iter.elt;
821
struct soap_dom_element &soap_dom_iterator::operator*() const
825
soap_dom_iterator &soap_dom_iterator::operator++()
827
{ if (this->elt->elts)
828
this->elt = elt->elts;
829
else if (this->elt->next)
830
this->elt = this->elt->next;
832
{ do this->elt = this->elt->prnt;
833
while (this->elt && !this->elt->next);
835
this->elt = this->elt->next;
839
if (this->name && this->elt->name)
840
{ if (!soap_tag_cmp(this->elt->name, this->name))
841
{ if (this->nstr && this->elt->nstr)
842
{ if (!soap_tag_cmp(this->elt->nstr, this->nstr))
850
{ if (this->elt->type == this->type)
865
std::ostream &operator<<(std::ostream &o, const struct soap_dom_element &e)
868
soap_init2(&soap, SOAP_IO_DEFAULT, SOAP_XML_GRAPH);
869
soap_mark_xsd__anyType(&soap, &e);
870
soap_begin_send(&soap);
871
soap_put_xsd__anyType(&soap, &e, NULL, NULL);
872
soap_end_send(&soap);
877
{ std::ostream *os = e.soap->os;
879
short omode = e.soap->omode;
880
soap_set_omode(e.soap, SOAP_XML_GRAPH);
881
soap_mark_xsd__anyType(e.soap, &e);
882
soap_begin_send(e.soap);
883
soap_put_xsd__anyType(e.soap, &e, NULL, NULL);
884
soap_end_send(e.soap);
886
e.soap->omode = omode;
891
std::istream &operator>>(std::istream &i, struct soap_dom_element &e)
894
std::istream *is = e.soap->is;
896
if (soap_begin_recv(e.soap)
897
|| !soap_in_xsd__anyType(e.soap, NULL, &e, NULL)
898
|| soap_end_recv(e.soap))
899
; /* handle error? Note: e.soap->error is set and app should check */