/******************************************************************/ /* XML2 block. Must have the same layout than FBLOCK up to Type. */ /******************************************************************/ typedefstruct _x2block { /* Loaded XML file block */ struct _x2block *Next;
LPCSTR Fname; /* Point on file name */
size_t Length; /* Used to tell if read mode */ short Count; /* Nb of times file is used */ short Type; /* TYPE_FB_XML */ int Retcode; /* Return code from Load */
xmlDocPtr Docp; /* Document interface pointer */
} X2BLOCK, *PX2BLOCK;
/******************************************************************/ /* Declaration of libxml2 document. */ /******************************************************************/ class LIBXMLDOC : public XMLDOCUMENT { friendclass XML2NODE; friendclass XML2ATTR; public: // Constructor
LIBXMLDOC(char *nsl, char *nsdf, char *enc, PFBLOCK fp);
// Properties short GetDocType(void) override {return TYPE_FB_XML2;} void *GetDocPtr(void) override {return Docp;} void SetNofree(bool b) override {Nofreelist = b;}
/******************************************************************/ /* Initialize XML parser and check library compatibility. */ /******************************************************************/ bool LIBXMLDOC::Initialize(PGLOBAL g, PCSZ entry, bool zipped)
{ if (zipped && InitZip(g, entry)) returntrue;
xmlKeepBlanksDefault(1); return MakeNSlist(g);
} // end of Initialize
/******************************************************************/ /* Parse the XML file and construct node tree in memory. */ /******************************************************************/ bool LIBXMLDOC::ParseFile(PGLOBAL g, char *fn)
{ if (trace(1))
htrc("ParseFile\n");
if (zip) { // Parse an in memory document char *xdoc = GetMemDoc(g, fn);
/******************************************************************/ /* Create or reuse an Xblock for this document. */ /******************************************************************/
PFBLOCK LIBXMLDOC::LinkXblock(PGLOBAL g, MODE m, int rc, char *fn)
{
PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
PX2BLOCK xp = (PX2BLOCK)PlugSubAlloc(g, NULL, sizeof(X2BLOCK));
// Return xp as a fp return (PFBLOCK)xp;
} // end of LinkXblock
/******************************************************************/ /* Construct and add the XML processing instruction node. */ /******************************************************************/ bool LIBXMLDOC::NewDoc(PGLOBAL g, PCSZ ver)
{ if (trace(1))
htrc("NewDoc\n");
return ((Docp = xmlNewDoc(BAD_CAST ver)) == NULL);
} // end of NewDoc
/******************************************************************/ /* Add a new comment node to the document. */ /******************************************************************/ void LIBXMLDOC::AddComment(PGLOBAL g, char *txtp)
{ if (trace(1))
htrc("AddComment: %-.256s\n", txtp);
xmlNodePtr cp = xmlNewDocComment(Docp, BAD_CAST txtp);
xmlAddChild((xmlNodePtr)Docp, cp);
} // end of AddText
/******************************************************************/ /* Return the node class of the root of the document. */ /******************************************************************/
PXNODE LIBXMLDOC::GetRoot(PGLOBAL g)
{ if (trace(1))
htrc("GetRoot\n");
xmlNodePtr root = xmlDocGetRootElement(Docp);
if (!root) return NULL;
returnnew(g) XML2NODE(this, root);
} // end of GetRoot
/******************************************************************/ /* Create a new root element and return its class node. */ /******************************************************************/
PXNODE LIBXMLDOC::NewRoot(PGLOBAL g, char *name)
{ if (trace(1))
htrc("NewRoot: %-.256s\n", name);
if (name) {
nop = xmlNewDocNode(Docp, NULL, BAD_CAST name, NULL);
if (nop == NULL) return NULL;
} else
nop = NULL;
returnnew(g) XML2NODE(this, nop);
} // end of NewPnode
/******************************************************************/ /* Return a void XML2ATTR node class. */ /******************************************************************/
PXATTR LIBXMLDOC::NewPattr(PGLOBAL g)
{ returnnew(g) XML2ATTR(this, NULL, NULL);
} // end of NewPattr
/******************************************************************/ /* Return a void XML2ATTR node class. */ /******************************************************************/
PXLIST LIBXMLDOC::NewPlist(PGLOBAL g)
{ returnnew(g) XML2NODELIST(this, NULL);
} // end of NewPlist
/******************************************************************/ /* Dump the node tree to a new XML file. */ /******************************************************************/ int LIBXMLDOC::DumpDoc(PGLOBAL g, char *ofn)
{ int rc = 0;
FILE *of;
if (trace(1))
htrc("DumpDoc: %-.256s\n", ofn);
if (!(of= global_fopen(g, MSGID_CANNOT_OPEN, ofn, "w"))) return -1;
#if1 // This function does not crash ( if (xmlSaveFormatFileEnc((constchar *)ofn, Docp, Encoding, 0) < 0) { const xmlError *err = xmlGetLastError();
strcpy(g->Message, (err) ? err->message : "Error saving XML doc");
xmlResetLastError();
rc = -1;
} // endif Save // rc = xmlDocDump(of, Docp); #else// 0 // Until this function is fixed, do the job ourself
xmlNodePtr Rootp;
// Save the modified document
fprintf(of, "<?xml version=\"1.0\" encoding=\"%-.256s\"?>\n", Encoding);
fprintf(of, "<!-- Created by CONNECT %-.256s -->\n", version);
if (!(Rootp = xmlDocGetRootElement(Docp))) return1;
if (trace(1))
htrc("Ns error: %-.256s\n", g->Message);
return NULL;
} // endif Registering
} // endfor nsp
} // endif Ctxp
if (Xop) { if (trace(1))
htrc("Calling xmlXPathFreeNodeSetList Xop=%p NOFREE=%d\n",
Xop, Nofreelist);
if (Nofreelist) { // Making Nlist that must not be freed yet // xmlXPathFreeNodeSetList(Xop); // Caused memory leak
assert(!NlXop);
NlXop = Xop; // Freed on closing
Nofreelist = false;
} else
xmlXPathFreeObject(Xop); // Caused node not found
#if0// Not used anymore /******************************************************************/ /* CheckDocument: check if the document is ok to dump. */ /* Currently this does the dumping of the document. */ /******************************************************************/ bool LIBXMLDOC::CheckDocument(FILE *of, xmlNodePtr np)
{ int n; bool b;
if (!np) returntrue;
if (np->type == XML_ELEMENT_NODE) {
n = fprintf(of, "<%s", np->name);
b = CheckDocument(of, (xmlNodePtr)np->properties);
if (np->children)
n = fprintf(of, ">"); else
n = fprintf(of, "/>");
int XML2NODE::GetType(void)
{ if (trace(1))
htrc("GetType type=%d\n", Nodep->type);
return Nodep->type;
} // end of GetType
/******************************************************************/ /* Return the node class of next sibling of the node. */ /******************************************************************/
PXNODE XML2NODE::GetNext(PGLOBAL g)
{ if (trace(1))
htrc("GetNext\n");
if (!Nodep->next)
Next = NULL; else// if (!Next)
Next = new(g) XML2NODE(Doc, Nodep->next);
return Next;
} // end of GetNext
/******************************************************************/ /* Return the node class of first children of the node. */ /******************************************************************/
PXNODE XML2NODE::GetChild(PGLOBAL g)
{ if (trace(1))
htrc("GetChild\n");
if (!Nodep->children)
Children = NULL; else// if (!Children)
Children = new(g) XML2NODE(Doc, Nodep->children);
return Children;
} // end of GetChild
/******************************************************************/ /* Return the content of a node and subnodes. */ /******************************************************************/
RCODE XML2NODE::GetContent(PGLOBAL g, char *buf, int len)
{
RCODE rc = RC_OK;
if (trace(1))
htrc("GetContent\n");
if (Content)
xmlFree(Content);
if ((Content = xmlNodeGetContent(Nodep))) { char *p1 = (char*)Content, *p2 = buf; bool b = false;
// Copy content eliminating extra characters for (; *p1; p1++) if ((p2 - buf) < len) { if (strchr(" \t\r\n", *p1)) { if (b) { // This to have one blank between sub-nodes
*p2++ = ' ';
b = false;
} // endif b
/******************************************************************/ /* Set the content of a node. */ /******************************************************************/ bool XML2NODE::SetContent(PGLOBAL g, char *txtp, int len)
{ if (trace(1))
htrc("SetContent: %-.256s\n", txtp);
/******************************************************************/ /* Return the list of all or matching children that are elements.*/ /******************************************************************/
PXLIST XML2NODE::GetChildElements(PGLOBAL g, char *xp, PXLIST lp)
{ if (trace(1))
htrc("GetChildElements: %-.256s\n", xp);
return SelectNodes(g, (xp) ? xp : (char*)"*", lp);
} // end of GetChildElements
/******************************************************************/ /* Return the list of nodes verifying the passed Xpath. */ /******************************************************************/
PXLIST XML2NODE::SelectNodes(PGLOBAL g, char *xp, PXLIST lp)
{ if (trace(1))
htrc("SelectNodes: %-.256s\n", xp);
/******************************************************************/ /* Add a new property to this node and return it. */ /******************************************************************/
PXATTR XML2NODE::AddProperty(PGLOBAL g, char *name, PXATTR ap)
{ if (trace(1))
htrc("AddProperty: %-.256s\n", name);
xmlAttrPtr atp = xmlNewProp(Nodep, BAD_CAST name, NULL);
if (atp) { if (ap) {
((PATTR2)ap)->Atrp = atp;
((PATTR2)ap)->Parent = Nodep; return ap;
} else returnnew(g) XML2ATTR(Doc, atp, Nodep);
} else return NULL;
} // end of AddProperty
/******************************************************************/ /* Add a new text node to this node. */ /******************************************************************/ void XML2NODE::AddText(PGLOBAL g, PCSZ txtp)
{ if (trace(1))
htrc("AddText: %-.256s\n", txtp);
// This is to avoid a blank line when inserting a new line
xmlNodePtr np = xmlGetLastChild(Nodep);
if (np && np->type == XML_TEXT_NODE) {
xmlUnlinkNode(np);
xmlFreeNode(np);
} // endif type
// Add the new text
xmlAddChild(Nodep, xmlNewText(BAD_CAST txtp));
} // end of AddText
/******************************************************************/ /* Remove a child node from this node. */ /******************************************************************/ void XML2NODE::DeleteChild(PGLOBAL g, PXNODE dnp)
{ const xmlError *xerr;
if (trace(1))
htrc("DeleteChild: node=%p\n", dnp);
xmlNodePtr np = ((PNODE2)dnp)->Nodep;
xmlNodePtr text = np->next;
// This is specific to row nodes if (text && text->type == XML_TEXT_NODE) {
xmlUnlinkNode(text);
if ((xerr = xmlGetLastError())) goto err;
xmlFreeNode(text);
if ((xerr = xmlGetLastError())) goto err;
} // endif type
xmlUnlinkNode(np);
if ((xerr = xmlGetLastError())) goto err;
xmlFreeNode(np);
if ((xerr = xmlGetLastError())) goto err;
Delete(dnp);
if ((xerr = xmlGetLastError())) goto err;
return;
err: if (trace(1))
htrc("DeleteChild: errmsg=%-.256s\n", xerr->message);
xmlResetLastError();
} // end of DeleteChild
/* -------------------- class XML2NODELIST ---------------------- */
/******************************************************************/ /* Return the length of the list. */ /******************************************************************/ int XML2NODELIST::GetLength(void)
{ return (Listp) ? Listp->nodeNr : 0;
} // end of GetLength
/******************************************************************/ /* Return the nth element of the list. */ /******************************************************************/
PXNODE XML2NODELIST::GetItem(PGLOBAL g, int n, PXNODE np)
{ if (trace(1))
htrc("GetItem: %d\n", n);
/******************************************************************/ /* Reset the pointer on the deleted item. */ /******************************************************************/ bool XML2NODELIST::DropItem(PGLOBAL g, int n)
{ if (trace(1))
htrc("DropItem: n=%d\n", n);
// We should do something here if (!Listp || Listp->nodeNr <= n) returntrue;
Listp->nodeTab[n] = NULL; // This was causing Valgrind warning returnfalse;
} // end of DropItem
/* ---------------------- class XML2ATTR ------------------------ */
/******************************************************************/ /* Return the next sibling of the attribute. */ /******************************************************************/
PXATTR XML2ATTR::GetNext(PGLOBAL g)
{ if (trace(1))
htrc("Attr GetNext\n");
if (!Atrp->next) return NULL; else returnnew(g) XML2ATTR(Doc, Atrp->next, Atrp->parent);
} // end of GetNext
/******************************************************************/ /* Return the text of an attribute. */ /******************************************************************/
RCODE XML2ATTR::GetText(PGLOBAL g, char *buf, int len)
{
RCODE rc = RC_OK;
xmlChar *txt;
if (trace(1))
htrc("GetText\n");
if ((txt = xmlGetProp(Atrp->parent, Atrp->name))) { // Copy the text to the buffer if (strlen((char*)txt) >= (unsigned)len) {
memcpy(buf, txt, len - 1);
buf[len - 1] = 0;
snprintf(g->Message, sizeof(g->Message), "Truncated %-.256s content", Atrp->name);
rc = RC_INFO;
} else
strcpy(buf, (constchar*)txt);
xmlFree(txt);
} else
*buf = '\0';
if (trace(1))
htrc("GetText: %-.256s\n", buf);
return rc;
} // end of GetText
/******************************************************************/ /* Set the content of an attribute. */ /******************************************************************/ bool XML2ATTR::SetText(PGLOBAL g, char *txtp, int len)
{ if (trace(1))
htrc("SetText: %-.256s %d\n", txtp, len);
xmlSetProp(Parent, Atrp->name, BAD_CAST txtp); returnfalse;
} // end of SetText
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.23 Sekunden
(vorverarbeitet am 2026-10-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.