cmXml.h/c : Added cmXmlSearch() functions.
This commit is contained in:
parent
dbd3da490e
commit
59bd46a15f
202
cmXml.c
202
cmXml.c
@ -11,9 +11,10 @@
|
|||||||
#include "cmLinkedHeap.h"
|
#include "cmLinkedHeap.h"
|
||||||
#include "cmFile.h"
|
#include "cmFile.h"
|
||||||
#include "cmXml.h"
|
#include "cmXml.h"
|
||||||
|
#include "cmText.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
To do:
|
To Do:
|
||||||
1) Escape node data strings and attribute values.
|
1) Escape node data strings and attribute values.
|
||||||
2) Attribute values must be quoted by they may be quoted with either single or double quotes.
|
2) Attribute values must be quoted by they may be quoted with either single or double quotes.
|
||||||
3) Consider not buffering the XML file and reading directly from the file.
|
3) Consider not buffering the XML file and reading directly from the file.
|
||||||
@ -131,39 +132,36 @@ cmXmlNode_t* _cmXmlNodeAlloc( cmXml_t* p, unsigned flags, const cmChar_t* label,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
cmXmlNode_t* n0p = NULL;
|
cmXmlNode_t* n0p = NULL;
|
||||||
cmXmlNode_t* n1p = p->stack->children;
|
cmXmlNode_t* n1p = p->stack->children;
|
||||||
|
|
||||||
for(; n1p != NULL; n1p=n1p->sibling )
|
for(; n1p != NULL; n1p=n1p->sibling )
|
||||||
n0p = n1p;
|
n0p = n1p;
|
||||||
|
|
||||||
n0p->sibling = np;
|
n0p->sibling = np;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// all new nodes are put on the top of the stack
|
||||||
p->stack = np;
|
p->stack = np;
|
||||||
|
|
||||||
if( cmIsFlag(flags,kRootXmlFl) )
|
// all nodes must have a valid 'type' flag
|
||||||
p->root = np;
|
if( (flags & kTypeXmlFlags) == 0 )
|
||||||
else
|
|
||||||
{
|
{
|
||||||
if( cmIsFlag(flags,kDeclXmlFl) )
|
_cmXmlSyntaxError(p);
|
||||||
{
|
return NULL;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if( cmIsFlag(flags,kDoctypeXmlFl ) )
|
|
||||||
p->doctype = np;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if( !cmIsFlag(flags,kNormalXmlFl ) )
|
|
||||||
{
|
|
||||||
_cmXmlSyntaxError(p);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if this is the root node
|
||||||
|
if( cmIsFlag(flags,kRootXmlFl) )
|
||||||
|
{
|
||||||
|
assert( p->root == NULL );
|
||||||
|
p->root = np;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if this is the 'doctype' node
|
||||||
|
if( cmIsFlag(flags,kDoctypeXmlFl ) )
|
||||||
|
p->doctype = np;
|
||||||
|
|
||||||
if( label != NULL )
|
if( label != NULL )
|
||||||
np->label = cmLhAllocStrN(p->heapH,label,labelN);
|
np->label = cmLhAllocStrN(p->heapH,label,labelN);
|
||||||
|
|
||||||
@ -674,8 +672,8 @@ cmXmlRC_t _cmXmlReadNode( cmXml_t* p, cmXmlNode_t* parent )
|
|||||||
|
|
||||||
cmXmlRC_t cmXmlParse( cmXmlH_t h, const cmChar_t* fn )
|
cmXmlRC_t cmXmlParse( cmXmlH_t h, const cmChar_t* fn )
|
||||||
{
|
{
|
||||||
cmXmlRC_t rc = kOkXmlRC;
|
cmXmlRC_t rc = kOkXmlRC;
|
||||||
cmXml_t* p = _cmXmlHandleToPtr(h);
|
cmXml_t* p = _cmXmlHandleToPtr(h);
|
||||||
cmXmlNode_t* np = NULL;
|
cmXmlNode_t* np = NULL;
|
||||||
|
|
||||||
cmLHeapClear( p->heapH, false );
|
cmLHeapClear( p->heapH, false );
|
||||||
@ -711,24 +709,35 @@ cmXmlRC_t cmXmlClear( cmXmlH_t h )
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cmXmlNode_t* cmXmlRoot( cmXmlH_t h )
|
||||||
|
{
|
||||||
|
cmXml_t* p = _cmXmlHandleToPtr(h);
|
||||||
|
return p->root;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void _cmXmlPrintNode( const cmXmlNode_t* np, cmRpt_t* rpt, unsigned indent )
|
void _cmXmlPrintNode( const cmXmlNode_t* np, cmRpt_t* rpt, unsigned indent )
|
||||||
{
|
{
|
||||||
cmChar_t s[ indent + 1 ];
|
cmChar_t s[ indent + 1 ];
|
||||||
memset(s,' ',indent);
|
memset(s,' ',indent);
|
||||||
s[indent] = 0;
|
s[indent] = 0;
|
||||||
|
|
||||||
|
// print indent and label
|
||||||
cmRptPrintf(rpt,"%s%s: ",s,np->label);
|
cmRptPrintf(rpt,"%s%s: ",s,np->label);
|
||||||
|
|
||||||
|
// print this node's attributes
|
||||||
cmXmlAttr_t* ap = np->attr;
|
cmXmlAttr_t* ap = np->attr;
|
||||||
for(; ap!=NULL; ap=ap->link)
|
for(; ap!=NULL; ap=ap->link)
|
||||||
cmRptPrintf(rpt,"%s='%s' ",ap->label,ap->value);
|
cmRptPrintf(rpt,"%s='%s' ",ap->label,ap->value);
|
||||||
|
|
||||||
|
// print this nodes data string
|
||||||
if( np->dataStr != NULL )
|
if( np->dataStr != NULL )
|
||||||
cmRptPrintf(rpt," (%s)",np->dataStr);
|
cmRptPrintf(rpt," (%s)",np->dataStr);
|
||||||
|
|
||||||
cmRptPrintf(rpt,"\n");
|
cmRptPrintf(rpt,"\n");
|
||||||
|
|
||||||
|
// print this nodes children via recursion
|
||||||
cmXmlNode_t* cnp = np->children;
|
cmXmlNode_t* cnp = np->children;
|
||||||
|
|
||||||
for(; cnp!=NULL; cnp=cnp->sibling )
|
for(; cnp!=NULL; cnp=cnp->sibling )
|
||||||
_cmXmlPrintNode(cnp,rpt,indent+2);
|
_cmXmlPrintNode(cnp,rpt,indent+2);
|
||||||
|
|
||||||
@ -742,6 +751,132 @@ void cmXmlPrint( cmXmlH_t h , cmRpt_t* rpt )
|
|||||||
_cmXmlPrintNode(p->root,rpt,0);
|
_cmXmlPrintNode(p->root,rpt,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cmXmlNode_t* cmXmlSearch( const cmXmlNode_t* np, const cmChar_t* label, const cmXmlAttr_t* attrV, unsigned attrN )
|
||||||
|
{
|
||||||
|
// if the 'label' matches this node's label ...
|
||||||
|
if( cmTextCmp(np->label,label) == 0 )
|
||||||
|
{
|
||||||
|
unsigned matchN = 0;
|
||||||
|
const cmXmlAttr_t* a = np->attr;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
// ... then check for attribute matches also.
|
||||||
|
for(i=0; i<attrN; ++i)
|
||||||
|
{
|
||||||
|
for(; a!=NULL; a=a->link)
|
||||||
|
{
|
||||||
|
if( cmTextCmp(a->label,attrV[i].label) == 0 && cmTextCmp(a->value,attrV[i].value) == 0 )
|
||||||
|
{
|
||||||
|
++matchN;
|
||||||
|
|
||||||
|
// if a match was found for all attributes then the return np as the solution
|
||||||
|
if( matchN == attrN )
|
||||||
|
return np;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this node did not match - try each of this nodes children
|
||||||
|
const cmXmlNode_t* cnp = np->children;
|
||||||
|
for(; cnp!=NULL; cnp=cnp->sibling)
|
||||||
|
if(( np = cmXmlSearch(cnp,label,attrV,attrN)) != NULL )
|
||||||
|
return np; // a child matched
|
||||||
|
|
||||||
|
// no match was found.
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cmXmlNode_t* cmXmlSearchV( const cmXmlNode_t* np, const cmChar_t* label, const cmXmlAttr_t* attrV, unsigned attrN, va_list vl )
|
||||||
|
{
|
||||||
|
|
||||||
|
while( label != NULL )
|
||||||
|
{
|
||||||
|
if((np = cmXmlSearch(np,label,attrV,attrN)) == NULL )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if((label = va_arg(vl,cmChar_t*)) != NULL)
|
||||||
|
{
|
||||||
|
attrV = va_arg(vl,const cmXmlAttr_t*);
|
||||||
|
attrN = va_arg(vl,unsigned);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return np;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cmXmlNode_t* cmXmlSearchN( const cmXmlNode_t* np, const cmChar_t* label, const cmXmlAttr_t* attrV, unsigned attrN, ... )
|
||||||
|
{
|
||||||
|
va_list vl;
|
||||||
|
va_start(vl,attrN);
|
||||||
|
np = cmXmlSearchV(np,label,attrV,attrN,vl);
|
||||||
|
va_end(vl);
|
||||||
|
return np;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmXmlRC_t cmXmlGetInt( const cmXmlNode_t* np, int* retRef, const cmChar_t* label, const cmXmlAttr_t* attrV, unsigned attrN, ... )
|
||||||
|
{
|
||||||
|
cmXmlRC_t rc = kNodeNotFoundXmlRC;
|
||||||
|
va_list vl;
|
||||||
|
|
||||||
|
va_start(vl,attrN);
|
||||||
|
|
||||||
|
// find the requsted node
|
||||||
|
if((np = cmXmlSearchV(np,label,attrV,attrN,vl)) != NULL )
|
||||||
|
{
|
||||||
|
// if the returned node does not have a data string
|
||||||
|
if( np->dataStr == NULL )
|
||||||
|
return kInvalidTypeXmlRC;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
|
||||||
|
// convert the string to an integer
|
||||||
|
strtol(np->dataStr,NULL,10);
|
||||||
|
|
||||||
|
if( errno != 0 )
|
||||||
|
return kInvalidTypeXmlRC;
|
||||||
|
|
||||||
|
rc = kOkXmlRC;
|
||||||
|
}
|
||||||
|
|
||||||
|
va_end(vl);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void _cmXmlPrintMeasure( const cmXmlNode_t* mnp )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
cmXmlRC_t _cmXmlPrintScore( cmXmlH_t h )
|
||||||
|
{
|
||||||
|
cmXmlRC_t rc = kOkXmlRC;
|
||||||
|
const int sN = 32;
|
||||||
|
cmChar_t s[sN+1];
|
||||||
|
unsigned maxMeasNumb = 4;
|
||||||
|
unsigned i;
|
||||||
|
cmXml_t* p = _cmXmlHandleToPtr(h);
|
||||||
|
|
||||||
|
for(i=0; i<=maxMeasNumb; ++i)
|
||||||
|
{
|
||||||
|
snprintf(s,sN,"%i",i);
|
||||||
|
cmXmlAttr_t aV[] =
|
||||||
|
{
|
||||||
|
{ "number",s }
|
||||||
|
};
|
||||||
|
|
||||||
|
const cmXmlNode_t* np;
|
||||||
|
if((np = cmXmlSearch(cmXmlRoot(h),"measure",aV,1)) == NULL )
|
||||||
|
return cmErrMsg(&p->err,kTestFailXmlRC,"Missing measure '%i'.",i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
cmXmlRC_t cmXmlTest( cmCtx_t* ctx, const cmChar_t* fn )
|
cmXmlRC_t cmXmlTest( cmCtx_t* ctx, const cmChar_t* fn )
|
||||||
{
|
{
|
||||||
@ -754,7 +889,18 @@ cmXmlRC_t cmXmlTest( cmCtx_t* ctx, const cmChar_t* fn )
|
|||||||
if((rc = cmXmlParse(h,fn)) != kOkXmlRC )
|
if((rc = cmXmlParse(h,fn)) != kOkXmlRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
cmXmlPrint(h,&ctx->rpt);
|
cmXmlAttr_t aV[] =
|
||||||
|
{
|
||||||
|
{ "id","P1"}
|
||||||
|
};
|
||||||
|
|
||||||
|
if( cmXmlSearch(cmXmlRoot(h),"part",aV,1) == NULL )
|
||||||
|
{
|
||||||
|
cmErrMsg(&ctx->err,kTestFailXmlRC,"Search failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
//cmXmlPrint(h,&ctx->rpt);
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
cmXmlFree(&h);
|
cmXmlFree(&h);
|
||||||
|
19
cmXml.h
19
cmXml.h
@ -10,8 +10,10 @@ extern "C" {
|
|||||||
kOkXmlRC = cmOkRC,
|
kOkXmlRC = cmOkRC,
|
||||||
kMemAllocErrXmlRC,
|
kMemAllocErrXmlRC,
|
||||||
kLHeapXmlRC,
|
kLHeapXmlRC,
|
||||||
kLexErrXmlRC,
|
kSyntaxErrorXmlRC,
|
||||||
kSyntaxErrorXmlRC
|
kTestFailXmlRC,
|
||||||
|
kInvalidTypeXmlRC,
|
||||||
|
kNodeNotFoundXmlRC
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct cmXmlAttr_str
|
typedef struct cmXmlAttr_str
|
||||||
@ -27,6 +29,7 @@ extern "C" {
|
|||||||
kDeclXmlFl = 0x0002,
|
kDeclXmlFl = 0x0002,
|
||||||
kDoctypeXmlFl = 0x0004,
|
kDoctypeXmlFl = 0x0004,
|
||||||
kNormalXmlFl = 0x0008,
|
kNormalXmlFl = 0x0008,
|
||||||
|
kTypeXmlFlags = kRootXmlFl | kDeclXmlFl | kDoctypeXmlFl | kNormalXmlFl,
|
||||||
kClosedXmlFl = 0x0010
|
kClosedXmlFl = 0x0010
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -55,9 +58,15 @@ extern "C" {
|
|||||||
cmXmlRC_t cmXmlFree( cmXmlH_t* hh );
|
cmXmlRC_t cmXmlFree( cmXmlH_t* hh );
|
||||||
bool cmXmlIsValid( cmXmlH_t h );
|
bool cmXmlIsValid( cmXmlH_t h );
|
||||||
|
|
||||||
cmXmlRC_t cmXmlParse( cmXmlH_t h, const cmChar_t* fn );
|
cmXmlRC_t cmXmlParse( cmXmlH_t h, const cmChar_t* fn );
|
||||||
cmXmlRC_t cmXmlClear( cmXmlH_t h );
|
cmXmlRC_t cmXmlClear( cmXmlH_t h );
|
||||||
void cmXmlPrint( cmXmlH_t h , cmRpt_t* rpt );
|
const cmXmlNode_t* cmXmlRoot( cmXmlH_t h );
|
||||||
|
void cmXmlPrint( cmXmlH_t h, cmRpt_t* rpt );
|
||||||
|
|
||||||
|
const cmXmlNode_t* cmXmlSearch( const cmXmlNode_t* np, const cmChar_t* label, const cmXmlAttr_t* attrV, unsigned attrN );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cmXmlRC_t cmXmlTest( cmCtx_t* ctx, const cmChar_t* fn );
|
cmXmlRC_t cmXmlTest( cmCtx_t* ctx, const cmChar_t* fn );
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user