/******************************************************************/ /* Implementation of XML document processing using MS DOM */ /* Author: Olivier Bertrand 2007 - 2013 */ /******************************************************************/ #include"my_global.h" #include <stdio.h> #ifdefined(_WIN32) //#include <windows.h> #ifdefined(MSX2) #import"msxml2.dll"//Does not exist on Vista #elifdefined(MSX3) #import"msxml3.dll"//Causes error C2872: DOMNodeType: ambiguous symbol ?? #elifdefined(MSX4) #import"msxml4.dll"//Causes error C2872: DOMNodeType: ambiguous symbol ?? #elifdefined(MSX6) #pragma warning(suppress : 4192) #import"msxml6.dll"//Causes error C2872: DOMNodeType: ambiguous symbol ?? #else// MSX4 #error MSX? is notdefined #endif// MSX usingnamespace MSXML2; #else #errorThis is a Windows implementation only #endif
/******************************************************************/ /* Return a DOMDOC as a XMLDOC. */ /******************************************************************/
PXDOC GetDomDoc(PGLOBAL g, char *nsl, char *nsdf, char *enc, PFBLOCK fp)
{ return (PXDOC) new(g) DOMDOC(nsl, nsdf, enc, fp);
} // end of GetDomDoc
/***********************************************************************/ /* Close a loaded DOM XML file. */ /***********************************************************************/ void CloseXMLFile(PGLOBAL g, PFBLOCK fp, bool all)
{
PXBLOCK xp = (PXBLOCK)fp;
/******************************************************************/ /* Initialize XML parser and check library compatibility. */ /******************************************************************/ bool DOMDOC::Initialize(PGLOBAL g, PCSZ entry, bool zipped)
{ if (zipped && InitZip(g, entry)) returntrue;
if (TestHr(g, CoInitialize(NULL))) returntrue;
if (TestHr(g, Docp.CreateInstance("msxml2.domdocument"))) returntrue;
return MakeNSlist(g);
} // end of Initialize
/******************************************************************/ /* Parse the XML file and construct node tree in memory. */ /******************************************************************/ bool DOMDOC::ParseFile(PGLOBAL g, char *fn)
{ bool b;
Docp->async = false;
if (zip) { // Parse an in memory document char *xdoc = GetMemDoc(g, fn);
// This is not equivalent to load for UTF8 characters // It is why get node content is not the same
b = (xdoc) ? (bool)Docp->loadXML((_bstr_t)xdoc) : false;
} else // Load the document
b = (bool)Docp->load((_bstr_t)fn);
if (!b) returntrue;
returnfalse;
} // end of ParseFile
/******************************************************************/ /* Create or reuse an Xblock for this document. */ /******************************************************************/
PFBLOCK DOMDOC::LinkXblock(PGLOBAL g, MODE m, int rc, char *fn)
{
PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
PXBLOCK xp = (PXBLOCK)PlugSubAlloc(g, NULL, sizeof(XBLOCK));
// Return xp as a fp return (PFBLOCK)xp;
} // end of LinkXblock
/******************************************************************/ /* Create the XML node. */ /******************************************************************/ bool DOMDOC::NewDoc(PGLOBAL g, PCSZ ver)
{ char buf[64];
MSXML2::IXMLDOMProcessingInstructionPtr pip;
snprintf(buf, sizeof(buf), "version=\"%s\" encoding=\"%s\"", ver, Encoding);
pip = Docp->createProcessingInstruction("xml", buf);
Docp->appendChild(pip); returnfalse;
} // end of NewDoc
/******************************************************************/ /* Add a comment to the document node. */ /******************************************************************/ void DOMDOC::AddComment(PGLOBAL g, char *com)
{
Docp->appendChild(Docp->createComment(com));
} // end of AddComment
/******************************************************************/ /* Return the node class of the root of the document. */ /******************************************************************/
PXNODE DOMDOC::GetRoot(PGLOBAL g)
{
MSXML2::IXMLDOMElementPtr root = Docp->documentElement;
if (root == NULL) return NULL;
returnnew(g) DOMNODE(this, root);
} // end of GetRoot
/******************************************************************/ /* Create a new root element and return its class node. */ /******************************************************************/
PXNODE DOMDOC::NewRoot(PGLOBAL g, char *name)
{
MSXML2::IXMLDOMElementPtr ep = Docp->createElement(name);
if (ep == NULL) return NULL;
Docp->appendChild(ep); returnnew(g) DOMNODE(this, ep);
} // end of NewRoot
if (name) if ((root = Docp->createElement(name)) == NULL) return NULL;
returnnew(g) DOMNODE(this, root);
} // end of NewPnode
/******************************************************************/ /* Return a void DOMATTR node class. */ /******************************************************************/
PXATTR DOMDOC::NewPattr(PGLOBAL g)
{ returnnew(g) DOMATTR(this, NULL);
} // end of NewPattr
/******************************************************************/ /* Return a void DOMATTR node class. */ /******************************************************************/
PXLIST DOMDOC::NewPlist(PGLOBAL g)
{ returnnew(g) DOMNODELIST(this, NULL);
} // end of NewPlist
/******************************************************************/ /* Dump the node tree to a new XML file. */ /******************************************************************/ int DOMDOC::DumpDoc(PGLOBAL g, char *ofn)
{ int rc = 0;
try {
Docp->save(ofn);
} catch(_com_error e) { int i = snprintf(g->Message, sizeof(g->Message), "%s: %s", MSG(COM_ERROR),
_com_util::ConvertBSTRToString(e.Description())); for (i--; i >= 0 && g->Message[i] == '\n'; i--)
g->Message[i] = 0;
rc = -1;
} catch(...) {}
return rc;
} // end of Dump
/******************************************************************/ /* Free the document, cleanup the XML library, and */ /* debug memory for regression tests. */ /******************************************************************/ void DOMDOC::CloseDoc(PGLOBAL g, PFBLOCK xp)
{
CloseXMLFile(g, xp, false);
CloseZip();
} // end of Close
/* ----------------------- class DOMNODE ------------------------ */
/******************************************************************/ /* DOMNODE constructor. */ /******************************************************************/
DOMNODE::DOMNODE(PXDOC dp, MSXML2::IXMLDOMNodePtr np) : XMLNODE(dp)
{
Docp = ((PDOMDOC)dp)->Docp;
Nodep = np;
Ws = NULL;
Len = 0;
Zip = (bool)dp->zip;
} // end of DOMNODE constructor
/******************************************************************/ /* Return the node class of next sibling of the node. */ /******************************************************************/
PXNODE DOMNODE::GetNext(PGLOBAL g)
{ if (Nodep->nextSibling == NULL)
Next = NULL; else// if (!Next)
Next = new(g) DOMNODE(Doc, Nodep->nextSibling);
return Next;
} // end of GetNext
/******************************************************************/ /* Return the node class of first children of the node. */ /******************************************************************/
PXNODE DOMNODE::GetChild(PGLOBAL g)
{ if (Nodep->firstChild == NULL)
Children = NULL; else// if (!Children)
Children = new(g) DOMNODE(Doc, Nodep->firstChild);
return Children;
} // end of GetChild
/******************************************************************/ /* Return the content of a node and subnodes. */ /******************************************************************/
RCODE DOMNODE::GetContent(PGLOBAL g, char *buf, int len)
{
RCODE rc = RC_OK;
// Nodep can be null for a missing HTML table column if (Nodep) { if (Zip) {
strcpy(buf, Nodep->text);
} elseif (!WideCharToMultiByte(CP_UTF8, 0, Nodep->text, -1,
buf, len, NULL, NULL)) {
DWORD lsr = GetLastError();
/******************************************************************/ /* Set the text content of an attribute. */ /******************************************************************/ bool DOMNODE::SetContent(PGLOBAL g, char *txtp, int len)
{ bool rc;
BSTR val;
if (len > Len || !Ws) {
Ws = (WCHAR*)PlugSubAlloc(g, NULL, (len + 1) * 2);
Len = len;
} // endif len
if (!MultiByteToWideChar(CP_UTF8, 0, txtp, strlen(txtp) + 1,
Ws, Len + 1)) {
snprintf(g->Message, sizeof(g->Message), MSG(WS_CONV_ERR), txtp); returntrue;
} // endif
val = SysAllocString(Ws);
rc = TestHr(g, Nodep->put_text(val));
SysFreeString(val); return rc;
} // end of SetContent
/******************************************************************/ /* Return a clone of this node. */ /******************************************************************/
PXNODE DOMNODE::Clone(PGLOBAL g, PXNODE np)
{ if (np) {
((PDOMNODE)np)->Nodep = Nodep; return np;
} else returnnew(g) DOMNODE(Doc, Nodep);
} // end of Clone
/******************************************************************/ /* Return the list of all or matching children that are elements.*/ /******************************************************************/
PXLIST DOMNODE::GetChildElements(PGLOBAL g, char *xp, PXLIST lp)
{
MSXML2::IXMLDOMNodeListPtr dnlp;
if (xp) { if (Nodep->nodeType == MSXML2::NODE_ELEMENT) {
MSXML2::IXMLDOMElementPtr ep = Nodep;
dnlp = ep->getElementsByTagName(xp);
} else return NULL;
/******************************************************************/ /* Add a new element child node to this node and return it. */ /******************************************************************/
PXNODE DOMNODE::AddChildNode(PGLOBAL g, PCSZ name, PXNODE np)
{ constchar *p, *pn; // char *p, *pn, *epf, *pf = NULL;
MSXML2::IXMLDOMNodePtr ep; // _bstr_t uri((wchar_t*)NULL);
#if0 // Is a prefix specified ? if ((p = strchr(name, ':'))) {
pf = BufAlloc(g, name, p - name);
// Is it the pseudo default prefix if (Doc->DefNs && !strcmp(pf, Doc->DefNs)) {
name = p + 1; // Suppress it from name
pf = NULL; // No real prefix
} // endif DefNs
} // endif p
// Look for matching namespace URI in context for (ep = Nodep; ep; ep = ep->parentNode) {
epf = (_bstr_t)ep->prefix;
if ((!pf && !epf) || (pf && epf && !strcmp(pf, epf))) {
uri = Nodep->namespaceURI; break;
} // endif
} // endfor ep
if ((wchar_t*)uri == NULL) { if (!pf)
pf = Doc->DefNs;
// Look for the namespace URI corresponding to this node if (pf) for (PNS nsp = Doc->Namespaces; nsp; nsp = nsp->Next) if (!strcmp(pf, nsp->Prefix)) {
uri = nsp->Uri; break;
} // endfor nsp
} // endif pns #endif// 0
// If name has the format m[n] only m is taken as node name if ((p = strchr(name, '[')))
pn = BufAlloc(g, name, (int)(p - name)); else
pn = name;
// Construct the element node with eventual namespace // ep = Docp->createNode(_variant_t("Element"), pn, uri);
ep = Docp->createElement(pn);
_bstr_t pfx = ep->prefix;
_bstr_t uri = ep->namespaceURI;
if (ep == NULL) return NULL;
Nodep->appendChild(ep); if (np)
((PDOMNODE)np)->Nodep = ep; else
np = new(g) DOMNODE(Doc, ep);
return NewChild(np);
} // end of AddChildNode
/******************************************************************/ /* Add a new property to this node and return it. */ /******************************************************************/
PXATTR DOMNODE::AddProperty(PGLOBAL g, char *name, PXATTR ap)
{
MSXML2::IXMLDOMAttributePtr atp = Docp->createAttribute(name);
if (atp) {
MSXML2::IXMLDOMElementPtr ep = Nodep;
ep->setAttributeNode(atp);
/******************************************************************/ /* Add a new text node to this node. */ /******************************************************************/ void DOMNODE::AddText(PGLOBAL g, PCSZ txtp)
{
MSXML2::IXMLDOMTextPtr tp= Docp->createTextNode((_bstr_t)txtp);
if (tp != NULL)
Nodep->appendChild(tp);
} // end of AddText
/******************************************************************/ /* Remove a child node from this node. */ /******************************************************************/ void DOMNODE::DeleteChild(PGLOBAL g, PXNODE dnp)
{
Nodep->removeChild(((PDOMNODE)dnp)->Nodep); // ((PDOMNODE)dnp)->Nodep->Release(); bad idea, causes a crash Delete(dnp);
} // end of DeleteChild
/* --------------------- class DOMNODELIST ---------------------- */
/******************************************************************/ /* Return the nth element of the list. */ /******************************************************************/
PXNODE DOMNODELIST::GetItem(PGLOBAL g, int n, PXNODE np)
{ if (Listp == NULL || Listp->length <= n) return NULL;
/******************************************************************/ /* Return the next attribute node. */ /* This funtion is implemented as needed by XMLColumns. */ /******************************************************************/
PXATTR DOMATTR::GetNext(PGLOBAL g)
{ if (!Nmp) return NULL;
if (++K >= Nmp->Getlength()) {
Nmp->reset();
Nmp = NULL;
K = 0; return NULL;
} // endif K
Atrp = Nmp->Getitem(K); returnthis;
} // end of GetNext
/******************************************************************/ /* Return the content of a node and subnodes. */ /******************************************************************/
RCODE DOMATTR::GetText(PGLOBAL g, char *buf, int len)
{
RCODE rc = RC_OK;
/******************************************************************/ /* Set the text content of an attribute. */ /******************************************************************/ bool DOMATTR::SetText(PGLOBAL g, char *txtp, int len)
{ bool rc;
BSTR val;
if (len > Len || !Ws) {
Ws = (WCHAR*)PlugSubAlloc(g, NULL, (len + 1) * 2);
Len = len;
} // endif len
if (!MultiByteToWideChar(CP_UTF8, 0, txtp, strlen(txtp) + 1,
Ws, Len + 1)) {
snprintf(g->Message, sizeof(g->Message), MSG(WS_CONV_ERR), txtp); returntrue;
} // endif
val = SysAllocString(Ws);
rc = TestHr(g, Atrp->put_text(val));
SysFreeString(val); return rc;
} // end of SetText
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.2 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.