gwenhywfar 5.14.1
xmlcmd_lxml.c
Go to the documentation of this file.
1/***************************************************************************
2 begin : Sat Apr 18 2018
3 copyright : (C) 2020 by Martin Preuss
4 email : martin@libchipcard.de
5
6 ***************************************************************************
7 * *
8 * This library is free software; you can redistribute it and/or *
9 * modify it under the terms of the GNU Lesser General Public *
10 * License as published by the Free Software Foundation; either *
11 * version 2.1 of the License, or (at your option) any later version. *
12 * *
13 * This library is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16 * Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public *
19 * License along with this library; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21 * MA 02111-1307 USA *
22 * *
23 ***************************************************************************/
24
25
26#ifdef HAVE_CONFIG_H
27# include <config.h>
28#endif
29
30
31
32#include "xmlcmd_lxml_p.h"
33
34#include <gwenhywfar/debug.h>
35#include <gwenhywfar/text.h>
36
37
38#include <ctype.h>
39
40
41GWEN_INHERIT(GWEN_XMLCOMMANDER, GWEN_XMLCMD_LXML)
42
43
44
45/* ------------------------------------------------------------------------------------------------
46 * forward declarations
47 * ------------------------------------------------------------------------------------------------
48 */
49
50static void GWENHYWFAR_CB _freeData(void *bp, void *p);
51static void *_handleXmlPath(const char *entry, void *data, int idx, uint32_t flags);
52
53GWEN_XMLCMD_LXML_TWOSTRINGS *_twoStrings_new();
54void _twoStrings_free(GWEN_XMLCMD_LXML_TWOSTRINGS *ts);
55GWEN_XMLCMD_LXML_TWOSTRINGS *_twoStrings_fromString(const char *source, uint8_t delimiter);
56
57
58
59
60/* ------------------------------------------------------------------------------------------------
61 * implementations
62 * ------------------------------------------------------------------------------------------------
63 */
64
65
67{
69 GWEN_XMLCMD_LXML *xcmd;
70
72 GWEN_NEW_OBJECT(GWEN_XMLCMD_LXML, xcmd);
73 GWEN_INHERIT_SETDATA(GWEN_XMLCOMMANDER, GWEN_XMLCMD_LXML, cmd, xcmd, _freeData);
74
75 xcmd->docRoot=documentRoot;
76 xcmd->dbRoot=dbRoot;
77 xcmd->tempDbRoot=GWEN_DB_Group_new("dbTempRoot");
78
79 xcmd->currentDbGroup=xcmd->dbRoot;
80 xcmd->currentTempDbGroup=xcmd->tempDbRoot;
81 xcmd->currentDocNode=documentRoot;
82
83 return cmd;
84}
85
86
87
88void _freeData(GWEN_UNUSED void *bp, void *p)
89{
90 GWEN_XMLCMD_LXML *xcmd;
91
92 xcmd=(GWEN_XMLCMD_LXML*) p;
93
94 GWEN_DB_Group_free(xcmd->tempDbRoot);
95 GWEN_FREE_OBJECT(xcmd);
96}
97
98
99
101{
102 GWEN_XMLCMD_LXML *xcmd;
103
104 assert(cmd);
105 xcmd=GWEN_INHERIT_GETDATA(GWEN_XMLCOMMANDER, GWEN_XMLCMD_LXML, cmd);
106 assert(xcmd);
107
108 return xcmd->docRoot;
109}
110
111
112
114{
115 GWEN_XMLCMD_LXML *xcmd;
116
117 assert(cmd);
118 xcmd=GWEN_INHERIT_GETDATA(GWEN_XMLCOMMANDER, GWEN_XMLCMD_LXML, cmd);
119 assert(xcmd);
120
121 return xcmd->currentDocNode;
122}
123
124
125
127{
128 GWEN_XMLCMD_LXML *xcmd;
129
130 assert(cmd);
131 xcmd=GWEN_INHERIT_GETDATA(GWEN_XMLCOMMANDER, GWEN_XMLCMD_LXML, cmd);
132 assert(xcmd);
133
134 xcmd->currentDocNode=n;
135}
136
137
138
140{
141 GWEN_XMLCMD_LXML *xcmd;
142
143 assert(cmd);
144 xcmd=GWEN_INHERIT_GETDATA(GWEN_XMLCOMMANDER, GWEN_XMLCMD_LXML, cmd);
145 assert(xcmd);
146
147 return xcmd->dbRoot;
148}
149
150
151
153{
154 GWEN_XMLCMD_LXML *xcmd;
155
156 assert(cmd);
157 xcmd=GWEN_INHERIT_GETDATA(GWEN_XMLCOMMANDER, GWEN_XMLCMD_LXML, cmd);
158 assert(xcmd);
159
160 return xcmd->currentDbGroup;
161}
162
163
164
166{
167 GWEN_XMLCMD_LXML *xcmd;
168
169 assert(cmd);
170 xcmd=GWEN_INHERIT_GETDATA(GWEN_XMLCOMMANDER, GWEN_XMLCMD_LXML, cmd);
171 assert(xcmd);
172
173 xcmd->currentDbGroup=db;
174}
175
176
177
179{
180 GWEN_XMLCMD_LXML *xcmd;
181
182 assert(cmd);
183 xcmd=GWEN_INHERIT_GETDATA(GWEN_XMLCOMMANDER, GWEN_XMLCMD_LXML, cmd);
184 assert(xcmd);
185
186 return xcmd->tempDbRoot;
187}
188
189
190
192{
193 GWEN_XMLCMD_LXML *xcmd;
194
195 assert(cmd);
196 xcmd=GWEN_INHERIT_GETDATA(GWEN_XMLCOMMANDER, GWEN_XMLCMD_LXML, cmd);
197 assert(xcmd);
198
199 return xcmd->currentTempDbGroup;
200}
201
202
203
205{
206 GWEN_XMLCMD_LXML *xcmd;
207
208 assert(cmd);
209 xcmd=GWEN_INHERIT_GETDATA(GWEN_XMLCOMMANDER, GWEN_XMLCMD_LXML, cmd);
210 assert(xcmd);
211
212 xcmd->currentTempDbGroup=db;
213}
214
215
216
218{
219 GWEN_XMLCMD_LXML *xcmd;
220
221 assert(cmd);
222 xcmd=GWEN_INHERIT_GETDATA(GWEN_XMLCOMMANDER, GWEN_XMLCMD_LXML, cmd);
223 assert(xcmd);
224
225 assert(xNode);
226
227 if (xcmd->currentStackPos<GWEN_XMLCMD_LXML_PATH_MAXDEPTH) {
228 xcmd->xmlNodeStack[xcmd->currentStackPos]=xNode;
229 xcmd->currentStackPos++;
230 xcmd->currentDocNode=xNode;
231 }
232 else {
233 DBG_ERROR(GWEN_LOGDOMAIN, "Stack full, SNH!");
234 abort();
235 }
236}
237
238
239
241{
242 GWEN_XMLCMD_LXML *xcmd;
243 xmlNodePtr xNode;
244
245 assert(cmd);
246 xcmd=GWEN_INHERIT_GETDATA(GWEN_XMLCOMMANDER, GWEN_XMLCMD_LXML, cmd);
247 assert(xcmd);
248
249 if (xcmd->currentStackPos>0) {
250 xNode=xcmd->xmlNodeStack[xcmd->currentStackPos-1];
251 if (xNode==NULL) {
252 DBG_ERROR(GWEN_LOGDOMAIN, "Nothing on stack");
253 assert(xNode);
254 }
255 xcmd->currentStackPos--;
256 xcmd->currentDocNode=xNode;
257 }
258}
259
260
261
262
263
264xmlNodePtr GWEN_XmlCommanderLibXml_GetXmlNode(xmlNodePtr n, const char *path, uint32_t flags)
265{
266 return (xmlNodePtr)GWEN_Path_HandleWithIdx(path, n, flags, _handleXmlPath);
267}
268
269
270
271xmlNodePtr GWEN_XmlCommanderLibXml_FindFirstElement(xmlNodePtr parent, const char *elemName)
272{
273 xmlNodePtr n;
274
275 n=parent->children;
276 while (n) {
277 if (n->type==XML_ELEMENT_NODE) {
278 if (n->name && strcmp((const char *)n->name, elemName)==0) {
279 return n;
280 }
281 }
282 n=n->next;
283 } /* while */
284
285 return NULL;
286}
287
288
289
290xmlNodePtr GWEN_XmlCommanderLibXml_FindNextElement(xmlNodePtr elem, const char *elemName)
291{
292 xmlNodePtr n;
293
294 assert(elem);
295 n=elem->next;
296 while (n) {
297 if (n->type==XML_ELEMENT_NODE) {
298 if (n->name && strcmp((const char *)n->name, elemName)==0) {
299 return n;
300 }
301 }
302 n=n->next;
303 } /* while */
304
305 return NULL;
306}
307
308
309
310int GWEN_XmlCommanderLibXml_SetXmlCharValue(xmlNodePtr n, const char *path, const char *value)
311{
312 xmlNodePtr node;
313
314 node=GWEN_XmlCommanderLibXml_GetXmlNode(n, path, 0);
315 if (!node) {
316 DBG_INFO(GWEN_LOGDOMAIN, "here");
317 return GWEN_ERROR_GENERIC;
318 }
319
320 xmlNodeSetContent(node, BAD_CAST value);
321
322 return 0;
323}
324
325
326
327const char *GWEN_XmlCommanderLibXml_GetXmlCharValue(xmlNodePtr n, const char *path, const char *defValue)
328{
329 xmlNodePtr node;
330
332 if (!node) {
333 DBG_INFO(GWEN_LOGDOMAIN, "path [%s] not found", path);
334 return defValue;
335 }
336 node=node->children;
337 if (node==0)
338 return defValue;
339
340 while (node) {
341 if (node->type==XML_TEXT_NODE) {
342 return (const char *)node->content;
343 }
344 node=node->next;
345 }
346
347 return defValue;
348}
349
350
351
352int GWEN_XmlCommanderLibXml_SetIntValue(xmlNodePtr n, const char *path, int value)
353{
354 char numbuf[32];
355
356 snprintf(numbuf, sizeof(numbuf)-1, "%d", value);
357 numbuf[sizeof(numbuf)-1]=0;
358 return GWEN_XmlCommanderLibXml_SetXmlCharValue(n, path, numbuf);
359}
360
361
362
363int GWEN_XmlCommanderLibXml_GetIntValue(xmlNodePtr n, const char *path, int defValue)
364{
365 const char *s;
366 int i;
367
369 if (s==NULL)
370 return defValue;
371 if (1!=sscanf(s, "%i", &i))
372 return defValue;
373 return i;
374}
375
376
377
378const char *GWEN_XmlCommanderLibXml_GetXmlCharValueByPath(xmlNodePtr elem, const char *path, const char *defValue)
379{
380 GWEN_XMLCMD_LXML_TWOSTRINGS *tsLevel1;
381
382 tsLevel1=_twoStrings_fromString(path, '@');
383 if (tsLevel1->string2) {
384 xmlNodePtr n;
385
386 /* really two strings, so string1 is node, string2 is property name */
388 if (n) {
389 GWEN_XMLCMD_LXML_TWOSTRINGS *tsLevel2;
390 const char *result=NULL;
391
392 tsLevel2=_twoStrings_fromString(tsLevel1->string2, ':');
393 if (tsLevel2->string2) {
394 /* really two strings, so string1 is namespace, string2 is property name */
395 result=(const char*) xmlGetNsProp(n, BAD_CAST tsLevel2->string2, BAD_CAST tsLevel2->string1);
396 }
397 else {
398 /* only one string, so no namespace given */
399 result=(const char*) xmlGetNoNsProp(n, BAD_CAST tsLevel2->string1);
400 }
401 if (result) {
402 _twoStrings_free(tsLevel2);
403 _twoStrings_free(tsLevel1);
404 return result;
405 } /* else fall-through */
406 _twoStrings_free(tsLevel2);
407 } /* else fall-through */
408 }
409 else {
410 xmlNodePtr n;
411
412 /* only one string, so string1 is node */
414 if (n) {
415 n=n->children;
416 while (n) {
417 if (n->type==XML_TEXT_NODE) {
418 _twoStrings_free(tsLevel1);
419 return (const char *)n->content;
420 }
421 n=n->next;
422 }
423 }
424 }
425 _twoStrings_free(tsLevel1);
426
427
428 DBG_INFO(GWEN_LOGDOMAIN, "path [%s] not found", path);
429 return defValue;
430}
431
432
433
434void GWEN_XmlCommanderLibXml_SetXmlCharValueByPath(xmlNodePtr elem, const char *path, const char *value)
435{
436 GWEN_XMLCMD_LXML_TWOSTRINGS *tsLevel1;
437
438 tsLevel1=_twoStrings_fromString(path, '@');
439 if (tsLevel1->string2) {
440 xmlNodePtr n;
441
442 /* really two strings, so string1 is node, string2 is property name */
443 n=GWEN_XmlCommanderLibXml_GetXmlNode(elem, tsLevel1->string1, 0);
444 if (n) {
445 GWEN_XMLCMD_LXML_TWOSTRINGS *tsLevel2;
446
447 tsLevel2=_twoStrings_fromString(tsLevel1->string2, ':');
448 if (tsLevel2->string2) {
449 xmlNsPtr nameSpace;
450
451 /* really two strings, so string1 is namespace, string2 is property name */
452 nameSpace=xmlSearchNs(n->doc, n, BAD_CAST tsLevel2->string1);
453 xmlNewNsProp(n, nameSpace, BAD_CAST tsLevel2->string2, BAD_CAST value);
454 }
455 else {
456 /* only one string, so no namespace given */
457 xmlNewProp(n, BAD_CAST tsLevel2->string1, BAD_CAST value);
458 }
459 _twoStrings_free(tsLevel2);
460 } /* else fall-through */
461 }
462 else {
463 xmlNodePtr n;
464
465 /* only one string, so string1 is node */
466 n=GWEN_XmlCommanderLibXml_GetXmlNode(elem, tsLevel1->string1, 0);
467 if (n)
468 xmlNodeSetContent(n, BAD_CAST value);
469 }
470 _twoStrings_free(tsLevel1);
471}
472
473
474
475
476
477
478void *_handleXmlPath(const char *entry, void *data, int idx, uint32_t flags)
479{
480 xmlNodePtr n;
481 xmlNodePtr nn;
482 int i;
483 xmlNsPtr nameSpace=NULL;
484 const char *p;
485 const char *name;
486
487 n=(xmlNodePtr)data;
488
489 name=entry;
490 p=strchr(entry, ':');
491 if (p) {
492 char prefix[32];
493 int plen;
494
495 plen=p-entry;
496 if (plen) {
497 if (plen>=sizeof(prefix)) {
498 DBG_ERROR(GWEN_LOGDOMAIN, "Prefix too long (%d>%d)", (int)plen, (int)sizeof(prefix));
499 return 0;
500 }
501 strncpy(prefix, entry, plen);
502 prefix[plen]=0;
503 nameSpace=xmlSearchNs(n->doc, n, BAD_CAST prefix);
504 if (!nameSpace) {
505 DBG_ERROR(GWEN_LOGDOMAIN, "Namespace \"%s\" not found", prefix);
506 return 0;
507 }
508 }
509 name=p+1;
510 }
511
512 /* check whether we are allowed to simply create the node */
513 if (
514 ((flags & GWEN_PATH_FLAGS_LAST) &&
515 (((flags & GWEN_PATH_FLAGS_VARIABLE) &&
516 (flags & GWEN_PATH_FLAGS_CREATE_VAR)) ||
517 (!(flags & GWEN_PATH_FLAGS_VARIABLE) &&
519 ) ||
520 (
521 !(flags & GWEN_PATH_FLAGS_LAST) &&
523 ) {
524 /* simply create the new variable/group */
525 if (idx!=0) {
526 DBG_ERROR(GWEN_LOGDOMAIN, "Index is not 0, not creating %s[%d]", entry, idx);
527 return 0;
528 }
529 DBG_VERBOUS(GWEN_LOGDOMAIN, "Unconditionally creating entry \"%s\"", entry);
530 nn=xmlNewChild(n, nameSpace, BAD_CAST name, NULL);
531 return nn;
532 }
533
534 /* find the node */
535
536 nn=n->children;
537 i=idx;
538 while (nn) {
539 if (nn->type==XML_ELEMENT_NODE) {
540 if (nn->name && strcmp((const char *)nn->name, name)==0) {
541 if (i--==0)
542 break;
543 }
544 }
545 nn=nn->next;
546 } /* while */
547
548 if (!nn) {
549 /* node not found, check, if we are allowed to create it */
550 if (
551 (!(flags & GWEN_PATH_FLAGS_LAST) &&
554 ) {
555 DBG_VERBOUS(GWEN_LOGDOMAIN, "Entry \"%s\" does not exist", entry);
556 return 0;
557 }
558 /* create the new variable/group */
559 if (idx!=0) {
560 DBG_INFO(GWEN_LOGDOMAIN, "Index is not 0, not creating %s[%d]",
561 entry, idx);
562 return 0;
563 }
565 "Entry \"%s\" not found, creating", entry);
566 nn=xmlNewChild(n, nameSpace, BAD_CAST name, NULL);
567 } /* if node not found */
568 else {
569 /* node does exist, check whether this is ok */
570 if (
571 ((flags & GWEN_PATH_FLAGS_LAST) &&
573 (!(flags & GWEN_PATH_FLAGS_LAST) &&
575 ) {
576 DBG_VERBOUS(GWEN_LOGDOMAIN, "Entry \"%s\" already exists", entry);
577 return 0;
578 }
579 }
580
581 return nn;
582}
583
584
585
586
587
588
589
590GWEN_XMLCMD_LXML_TWOSTRINGS *_twoStrings_new()
591{
592 GWEN_XMLCMD_LXML_TWOSTRINGS *ts;
593
594 GWEN_NEW_OBJECT(GWEN_XMLCMD_LXML_TWOSTRINGS, ts);
595 return ts;
596}
597
598
599
600void _twoStrings_free(GWEN_XMLCMD_LXML_TWOSTRINGS *ts)
601{
602 if (ts) {
603 if (ts->ownStringsBitmap & 1) {
604 if (ts->string1)
605 free(ts->string1);
606 }
607 if (ts->ownStringsBitmap & 2) {
608 if (ts->string2)
609 free(ts->string2);
610 }
612 }
613}
614
615
616
617GWEN_XMLCMD_LXML_TWOSTRINGS *_twoStrings_fromString(const char *source, uint8_t delimiter)
618{
619 const char *s;
620 GWEN_XMLCMD_LXML_TWOSTRINGS *ts;
621
622 ts=_twoStrings_new();
623
624 s=strchr(source, delimiter);
625 if (s) {
626 int idx;
627
628 idx=s-source;
629 ts->string1=GWEN_Text_strndup(source, idx);
630 ts->ownStringsBitmap|=1;
631 s++;
632 if (s &&*s)
633 ts->string2=(char*)s;
634
635 return ts;
636 }
637 else {
638 ts->string1=(char*)source;
639 return ts;
640 }
641}
642
643
644
645
#define NULL
Definition binreloc.c:300
GWEN_DB_NODE * GWEN_DB_Group_new(const char *name)
Definition db.c:173
void GWEN_DB_Group_free(GWEN_DB_NODE *n)
Definition db.c:421
struct GWEN_DB_NODE GWEN_DB_NODE
Definition db.h:228
#define DBG_VERBOUS(dbg_logger, format,...)
Definition debug.h:224
#define DBG_INFO(dbg_logger, format,...)
Definition debug.h:181
#define DBG_ERROR(dbg_logger, format,...)
Definition debug.h:97
#define GWEN_ERROR_GENERIC
Definition error.h:62
#define GWEN_UNUSED
#define GWENHYWFAR_CB
#define GWEN_INHERIT_SETDATA(bt, t, element, data, fn)
Definition inherit.h:300
#define GWEN_INHERIT(bt, t)
Definition inherit.h:264
#define GWEN_INHERIT_GETDATA(bt, t, element)
Definition inherit.h:279
#define GWEN_LOGDOMAIN
Definition logger.h:32
#define GWEN_FREE_OBJECT(varname)
Definition memory.h:61
#define GWEN_NEW_OBJECT(typ, varname)
Definition memory.h:55
static void GWENHYWFAR_CB _freeData(GWEN_UNUSED void *bp, void *p)
Definition nogui.c:222
void * GWEN_Path_HandleWithIdx(const char *path, void *data, uint32_t flags, GWEN_PATHIDXHANDLERPTR elementFunction)
Definition path.c:210
#define GWEN_PATH_FLAGS_CREATE_GROUP
Definition path.h:96
#define GWEN_PATH_FLAGS_PATHMUSTEXIST
Definition path.h:66
#define GWEN_PATH_FLAGS_PATHCREATE
Definition path.h:78
#define GWEN_PATH_FLAGS_NAMEMUSTNOTEXIST
Definition path.h:89
#define GWEN_PATH_FLAGS_CREATE_VAR
Definition path.h:103
#define GWEN_PATH_FLAGS_LAST
Definition path.h:166
#define GWEN_PATH_FLAGS_PATHMUSTNOTEXIST
Definition path.h:70
#define GWEN_PATH_FLAGS_VARIABLE
Definition path.h:111
#define GWEN_PATH_FLAGS_NAMEMUSTEXIST
Definition path.h:84
char * GWEN_Text_strndup(const char *s, size_t n)
Definition text.c:2088
GWEN_XMLCOMMANDER * GWEN_XmlCommander_new(void)
Definition xmlcmd.c:46
struct GWEN_XMLCOMMANDER GWEN_XMLCOMMANDER
Definition xmlcmd.h:39
void GWEN_XmlCommanderLibXml_SetXmlCharValueByPath(xmlNodePtr elem, const char *path, const char *value)
xmlNodePtr GWEN_XmlCommanderLibXml_FindFirstElement(xmlNodePtr parent, const char *elemName)
static void * _handleXmlPath(const char *entry, void *data, int idx, uint32_t flags)
int GWEN_XmlCommanderLibXml_GetIntValue(xmlNodePtr n, const char *path, int defValue)
void GWEN_XmlCommanderLibXml_EnterDocNode(GWEN_XMLCOMMANDER *cmd, xmlNodePtr xNode)
void GWEN_XmlCommanderLibXml_LeaveDocNode(GWEN_XMLCOMMANDER *cmd)
void _twoStrings_free(GWEN_XMLCMD_LXML_TWOSTRINGS *ts)
int GWEN_XmlCommanderLibXml_SetXmlCharValue(xmlNodePtr n, const char *path, const char *value)
GWEN_DB_NODE * GWEN_XmlCommanderLibXml_GetTempDbRoot(const GWEN_XMLCOMMANDER *cmd)
static void GWENHYWFAR_CB _freeData(void *bp, void *p)
GWEN_DB_NODE * GWEN_XmlCommanderLibXml_GetCurrentTempDbGroup(const GWEN_XMLCOMMANDER *cmd)
const char * GWEN_XmlCommanderLibXml_GetXmlCharValue(xmlNodePtr n, const char *path, const char *defValue)
GWEN_XMLCOMMANDER * GWEN_XmlCommanderLibXml_new(xmlNodePtr documentRoot, GWEN_DB_NODE *dbRoot)
Definition xmlcmd_lxml.c:66
xmlNodePtr GWEN_XmlCommanderLibXml_FindNextElement(xmlNodePtr elem, const char *elemName)
xmlNodePtr GWEN_XmlCommanderLibXml_GetXmlNode(xmlNodePtr n, const char *path, uint32_t flags)
xmlNodePtr GWEN_XmlCommanderLibXml_GetCurrentDocNode(const GWEN_XMLCOMMANDER *cmd)
xmlNodePtr GWEN_XmlCommanderLibXml_GetDocRoot(const GWEN_XMLCOMMANDER *cmd)
const char * GWEN_XmlCommanderLibXml_GetXmlCharValueByPath(xmlNodePtr elem, const char *path, const char *defValue)
void GWEN_XmlCommanderLibXml_SetCurrentDocNode(GWEN_XMLCOMMANDER *cmd, xmlNodePtr n)
void GWEN_XmlCommanderLibXml_SetCurrentDbGroup(GWEN_XMLCOMMANDER *cmd, GWEN_DB_NODE *db)
int GWEN_XmlCommanderLibXml_SetIntValue(xmlNodePtr n, const char *path, int value)
GWEN_XMLCMD_LXML_TWOSTRINGS * _twoStrings_new()
GWEN_DB_NODE * GWEN_XmlCommanderLibXml_GetDbRoot(const GWEN_XMLCOMMANDER *cmd)
void GWEN_XmlCommanderLibXml_SetCurrentTempDbGroup(GWEN_XMLCOMMANDER *cmd, GWEN_DB_NODE *db)
GWEN_DB_NODE * GWEN_XmlCommanderLibXml_GetCurrentDbGroup(const GWEN_XMLCOMMANDER *cmd)
GWEN_XMLCMD_LXML_TWOSTRINGS * _twoStrings_fromString(const char *source, uint8_t delimiter)