Parsing part of XML file - c

So i am stuck on this for quite some time now. I use libxml2 and it works great for another part in the code but i cant seem to figure this one out and its bugging me like crazy.
I have this xml code:
<MetaCommandSet>
<MetaCommand name="ChangeSystemInterval">
<ArgumentList>
<Argument name="Interval" argumentTypeRef="UnsignedByteType"></Argument>
</ArgumentList>
</MetaCommand>
Now what i want is the name of the command and its arguments. This means that it has to stay in the same meta command so that i can collect al the arguments and than save this to for example a struct.
Code snippet:
for (cur_node = a_node; cur_node; cur_node = cur_node->next)
{
DATA TM_tmp;
COMMAND TC_tmp;
if(!xmlStrcmp(cur_node->name, "MetaCommand"))
{
TC_tmp.functionName = malloc(strlen((xmlGetProp(cur_node, "name") + 1)));
TC_tmp.functionName = xmlGetProp(cur_node, "name");
printf("Name: %s\n",TC_tmp.functionName);
/*
It now needs to keep looping this so i get every argument but it cant find any childs after argumentList
*/
}
createArray(cur_node->children);
I am nog getting further than getting the MetaCommand name. I am already looping threw all elements and if its a MetaCommand element i want to proceed with what i stated above.
Please give me some ideas

taken from one of my source coeds. You have to dive one level deeper than me, i have < pricing>< price age_group="">< EUR>...< /EUR>< /pricing>< /price>
{
while (cur != NULL) {
if (xmlStrcmp(cur->name, (const xmlChar *) "pricing") == 0) {
cur = cur->xmlChildrenNode;
while (cur != NULL) {
if (xmlStrcmp(cur->name, (const xmlChar *) "price") == 0) {
xmlNodePtr node = cur->xmlChildrenNode;
if (*kopf == NULL) {
*kopf = (Pricing *)HeapMalloc(sizeof(Pricing), "Pricing", 0);
ret = *kopf;
} else {
ret->next = (Pricing *)HeapMalloc(sizeof(Pricing), "Pricing", 0);
ret = ret->next;
}
parseAttribut(cur, "age_group", &(ret->age_group), fehler);
parseElement(doc, node, "EUR", &(ret->price), fehler);
}
cur = cur->next;
}
break;
}
cur = cur->next;
}
}
void parseAttribut(xmlNodePtr node, const xmlChar *str, xmlChar **dest, short muss, short *fehler)
{
*dest = xmlGetProp(node, str);
return;
}
void parseElement(xmlDocPtr doc, xmlNodePtr node, const xmlChar *str, xmlChar **dest, short muss, short *fehler)
{
short found = FALSE;
while (node) {
if (xmlStrcmp(node->name, str) == 0) {
*dest = xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
found = TRUE;
break;
}
node = node->next;
}
return;
}

Related

Libxml issue to get the attribute of a tag

I want to get only the value of attribut Object but if don't work after the first node because it don't enter in the loop, why ?
This is my xml file:
<msg><tag date="1557417027960" session="1697"><decision object="BAST04HEF" reliability="95" context="RO" x="796" y="371"
width="89" height="18"
direction="front"><jpeg></jpeg></decision></tag></msg>
And this my code:
int main(int argc, char **argv) {
char *docname;
xmlDocPtr doc;
xmlNodePtr cur;
xmlChar *object;
if (argc < 2) {
printf("Commande: %s nom_du_fichier\n", argv[0]);
return EXIT_FAILURE;
}
docname = argv[1];
doc = xmlParseFile(docname);
cur = xmlDocGetRootElement(doc);
cur = cur->xmlChildrenNode;
while (cur != NULL) {
if ((!xmlStrcmp(cur->name, (const xmlChar *)"decision"))) {
object = xmlGetProp(cur, "object");
printf("object: %s\n", object);
xmlFree(object);
}
cur = cur->next;
}
xmlFreeDoc(doc);
return EXIT_SUCCESS;
}
Your code processes only one level children, i.e. the direct children of the root element.
cur = xmlDocGetRootElement(doc); gets the root element.
cur = cur->xmlChildrenNode; gets the first (direct) child of the root element.
In you loop you get all siblings of this first child with cur = cur->next;, but you don't process their possible children.
Your XML snippet shows that you have at least three layers: msg - tag - decision.
If you want to process all decision elements regardless of what their parents are, you could use a recursive function.
static void processChildren(xmlNodePtr cur)
int main(int argc, char **argv) {
char *docname;
xmlDocPtr doc;
xmlNodePtr cur;
xmlChar *object;
if (argc < 2) {
printf("Commande: %s nom_du_fichier\n", argv[0]);
return EXIT_FAILURE;
}
docname = argv[1];
doc = xmlParseFile(docname);
cur = xmlDocGetRootElement(doc);
processChildren(cur->xmlChildrenNode);
xmlFreeDoc(doc);
return EXIT_SUCCESS;
}
static void processChildren(xmlNodePtr cur)
{
while (cur != NULL) {
if ((!xmlStrcmp(cur->name, (const xmlChar *)"decision"))) {
object = xmlGetProp(cur, "object");
printf("object: %s\n", object);
xmlFree(object);
}
else
{
processChildren(cur->children);
}
cur = cur->next;
}
}

linkisted have a pointer for required data

I have a linked list , which has full information
typdef struct details
{
struct details *head, *next, *curr;
char* values;
}
Details *fyllinfo ; //(this strcuct has full information)
/* fyllinfo this has been filled with many vallues*/
Now I need to copy the pointers to new list which can point only my required or matched data
Details *required;
char* myValue;
details *pstPtr =fyllinfo->head;
details *required = (details*) malloc(
sizeof(details));
required->head = required->next = NULL;
while(pstPtr != NULL)
{
if(NULL == pstPtr->values) goto NEXT;
printf("UUID FOUND IS [%s] and comapre with [%s] ",pstPtr->values,myvalue);
if(strCmp(pstPtr->values,myvalue)==0)
{
if(required->head == NULL)
{
required->head = required->curr = pstPtr;
}
else
{
required->next = pstPtr;
required->curr->next = pstPtr;
}
}
NEXT: pstPtr = pstPtr->next;
}
My Required ptr should have the pointer to only matched values
My code only points the first matched data and it has unmatched data in reuired->next pointer
This code works now... you just need to put some effort to understand it. you should be able to print the values. see how values are stored now.
details *pstPtr = fyllinfo;
details *required = NULL; //(details*)malloc(
details *head=NULL;
while (pstPtr != NULL)
{
if (1 == pstPtr->values)
printf("UUID FOUND IS [%d] and comapre with [%d] \n", pstPtr->values, 1);
if (pstPtr->values==1)
{
if (required == NULL)
{
required = (details*)malloc( sizeof(details));
head = required;
required->head = required->curr = pstPtr;
required->next = NULL;
}
else
{
required->next = (details*)malloc(sizeof(details));
required = required->next;
required->next = NULL;
required->curr = pstPtr;
}
}
pstPtr = pstPtr->next;
}
void display(struct details *r)
{
// r = fyllinfo;
if (r == NULL)
{
return;
}
while (r != NULL)
{
printf("%d ", r->curr->values);
r = r->next;
}
printf("\n");
}

xmlNewChild not always writing the value of the element

I have a very weird error with the xmlNewChild function using libxml2. I tried to keep the post as short as possible so I removed some insignificant logic. A boolean variable is defined for each variable to be written and when setting the variable value, the boolean is set to TRUE indicating if the tag is present, and if it is, it's written, otherwise is skipped
I have defined a structure as follows:
tyedef struct _xml_parse_t
{
const char *name;
void *variable;
int type;
_xml_parse_t *childs;
} xml_parse_t;
Another function parses this structure and writes it to a char*. the function is defined as follows:
int generate_xml(xml_parse_t *p, char *out, const char*root)
{
xmlChar *s = NULL;
int size = 0;
xmlDocPtr doc = NULL;
xmlNodePtr root_node = NULL;
doc = xmlNewDoc(NULL);
if(NULL == doc)
return -1;
root_node = xmlNewNode(NULL, BAD_CAST root);
if(NULL == root_node)
return -1;
else
xmlDocSetRootElement(doc, root_node);
if(-1 == writeXmlToDoc(p, doc, root_node))
return -1;
xmlDocDumpFormatMemoryEnc(doc, &s, &size, "UTF-8", 1);
if(NULL == s)
return -1;
if(SUCCEED == ret)
strcpy(out, (char *)s);
if(NULL != s)
xmlFree(s);
xmlFreeDoc(doc);
xmlCleanupParser();
xmlMemoryDump();
return 0;
}
The writeXmlToDoc is defined as below
int writeXmlToDoc(xml_parse_t *parse, xmlDocPtr doc,
xmlNodePtr root_node)
{
xml_parse_t *p = parse;
xmlNodePtr node;
while(NULL != p->name)
{
if( NODE_TYPE_PARENT == p->type && NULL != p->childs)
{
node = xmlNewChild(root_node, NULL, BAD_CAST p->name, NULL);
if(-1 == writeXmlToDoc(p->childs, doc, node))
return -1;
}
else
{
printf("Current value being written [%s]", (char *)cvtToXmlChar(p->variable, p->type));
node = xmlNewChild(root_node, NULL, BAD_CAST p->name,
BAD_CAST cvtToXmlChar(p->variable, p->type));
}
p++;
}
return 0;
}
To keep this post as short as possible, the cvtToXmlChar checks the type of the variable and casts it to xmlChar and the printf before the xmlNewChild is showing correct value of the variable.
xml_parse_t child_parse[] = {
/* Name var Type Childs*/
{"ChildInt", &test_int1, NODE_TYPE_INT, NULL },
{"ChildLong", &test_long1, NODE_TYPE_LONG, NULL },
{"ChildChar", test_char1, NODE_TYPE_STRING, NULL },
{"ChildShort", &test_short1, NODE_TYPE_SHORT, NULL },
{"ChildDouble", &test_double1,NODE_TYPE_DOUBLE, NULL },
{ NULL }
};
xml_parse_t parent_parse[] = {
/* Name var Type Childs*/
{"ParentInt", &test_int, NODE_TYPE_INT, NULL },
{"ParentLong", &test_long, NODE_TYPE_LONG, NULL },
{"ParentChar", test_char, NODE_TYPE_STRING, NULL },
{"ParentShort", &test_short, NODE_TYPE_SHORT, NULL },
{"ParentDouble", &test_double, NODE_TYPE_DOUBLE, NULL },
{"ParentParent", NULL, NODE_TYPE_PARENT, child_parse },
{ NULL }
};
and the variables set as follows:
test_int = 1;
test_int1 = 2;
test_long = 1;
test_long1 = 2;
sprintf(test_char, "TestParentCharTag");
sprintf(test_char1, "TestChildCharTag");
test_short = 1;
test_short1 = 2;
test_double = 1;
test_double1 = 2;
The problem is, the output string has 2 missing values. Following is the output of running the test
<ROOTELEMENT>
<ParentInt>1</ParentInt>
<ParentLong></ParentLong>
<ParentChar>TestParentCharTag</ParentChar>
<ParentShort>1</ParentShort>
<ParentDouble>1.000000</ParentDouble>
<ParentParent>
<ChildInt></ChildInt>
<ChildLong>2</ChildLong>
<ChildChar>TestChildCharTag</ChildChar>
<ChildShort>2</ChildShort>
<ChildDouble>2.000000</ChildDouble>
</ParentParent>
</ROOTELEMENT>
I'm not sure why but I had to use
xmlNodeSetContent(node, BAD_CAST cvtToXmlChar(variable, type));
after using the xmlNewChild.
I'm not sure about this solution (it's not really the best one) but it did the trick.
I still appreciate if I can get an explanation on the behavior above.

xmlNode path components

I'm trying to find a structure, function or macro in libxml2 that would allow me to access path components of an xmlNode. For example, if xmlGetNodePath returns /xml/a/b/c[42], where can I get just the position (42) or a component like b?
Thanks!
Here is your solution (Only if I get your question correctly).
Please check it with your requirement.
// XMLParse.cpp : Defines the entry point for the console application.
//
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <libxml/tree.h>
/*
* A person record
*/
typedef struct person {
char *name;
char *email;
char *company;
char *organisation;
char *smail;
char *webPage;
char *phone;
} person, *personPtr;
/*
* a Description for a Job
*/
typedef struct job {
char *projectID;
char *application;
char *category;
personPtr contact;
int nbDevelopers;
personPtr developers[100]; /* using dynamic alloc is left as an exercise */
} job, *jobPtr;
/*
* And the code needed to parse it
*/
personPtr parsePerson(xmlDocPtr doc, xmlNodePtr cur) {
personPtr ret = NULL;
//DEBUG("parsePerson\n");
/*
* allocate the struct
*/
ret = (personPtr) malloc(sizeof(person));
if (ret == NULL) {
fprintf(stderr,"out of memory\n");
return(NULL);
}
memset(ret, 0, sizeof(person));
/* We don't care what the top level element name is */
cur = cur->xmlChildrenNode;
while (cur != NULL) {
if ((!strcmp(cur->name, "Person")) )
ret->name = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
if ((!strcmp(cur->name, "Email")) )
ret->email = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
cur = cur->next;
}
return(ret);
}
/*
* And the code needed to parse it
*/
jobPtr parseJob(xmlDocPtr doc, xmlNodePtr cur) {
jobPtr ret = NULL;
//DEBUG("parseJob\n");
/*
* allocate the struct
*/
ret = (jobPtr) malloc(sizeof(job));
if (ret == NULL) {
fprintf(stderr,"out of memory\n");
return(NULL);
}
memset(ret, 0, sizeof(job));
/* We don't care what the top level element name is */
cur = cur->xmlChildrenNode;
cur = cur->next;
cur = cur->xmlChildrenNode;
cur = cur->next;
cur = cur->xmlChildrenNode;
while (cur != NULL) {
if ((!strcmp(cur->name, "Project")) ) {
ret->projectID = xmlGetProp(cur, "ID");
if (ret->projectID == NULL) {
fprintf(stderr, "Project has no ID\n");
}
}
if ((!strcmp(cur->name, "Application")) )
ret->application = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
if ((!strcmp(cur->name, "Category")) )
ret->category = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
if ((!strcmp(cur->name, "Contact")) )
ret->contact = parsePerson(doc,cur);
cur = cur->next;
}
return(ret);
}
int main(int argc, char* argv[])
{
jobPtr mainret = NULL;
xmlDocPtr doc;
xmlNodePtr cur;
doc = xmlParseFile("D://XMLParser/XMLParser1.0/comman/bin/myxml.xml");
if (doc == NULL ) {
fprintf(stderr,"Document not parsed successfully. \n");
return 0;
}
cur = xmlDocGetRootElement(doc);
if (cur == NULL) {
fprintf(stderr,"empty document\n");
xmlFreeDoc(doc);
return 0;
}
mainret = parseJob(doc,cur);
xmlFreeDoc(doc);
return 0;
}
Check it and let me know if I am wrong.

Finding a node in xml file with libxml2

I am trying to write a function that will find a node with a specified name in a xml file.
The problem is that the function never finds the specified node.
xmlNodePtr findNodeByName(xmlNodePtr rootnode, const xmlChar * nodename)
{
xmlNodePtr node = rootnode;
if(node == NULL){
log_err("Document is empty!");
return NULL;
}
while(node != NULL){
if(!xmlStrcmp(node->name, nodename)){
return node;
}
else if(node->children != NULL){
node = node->children;
xmlNodePtr intNode = findNodeByName(node, nodename);
if(intNode != NULL){
return intNode;
}
}
node = node->next;
}
return NULL;
}
I can see in the debugger that function does go deep into the sub nodes but still returns NULL.
Thanks in advance.
else if(node->children != NULL) {
node = node->children;
xmlNodePtr intNode = findNodeByName(node, nodename);
if (intNode != NULL) {
return intNode;
}
}
This should be:
else if (node->children != NULL) {
xmlNodePtr intNode = findNodeByName(node->children, nodename);
if(intNode != NULL) {
return intNode;
}
}
and it works fine
Your function is correct. Add a debugging line to see why it doesn't work in your case. For example:
printf("xmlStrcmp(%s, %s)==%d\n", node->name, nodename,
xmlStrcmp(node->name, nodename));
But you don't really need that function. You may use xmlXPathEval.
When #jarekczek mentionned XPath, he means to use XPath instead of your function.
With XPath, your function will become:
xmlNodeSetPtr findNodesByName(xmlDocPtr doc, xmlNodePtr rootnode, const xmlChar* nodename) {
// Create xpath evaluation context
xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc);
if(xpathCtx == NULL) {
fprintf(stderr,"Error: unable to create new XPath context\n");
return NULL;
}
// The prefix './/' means the nodes will be selected from the current node
const xmlChar* xpathExpr = xmlStrncatNew(".//", nodename, -1);
xmlXPathObjectPtr xpathObj = xmlXPathNodeEval(rootnode, xpathExpr, xpathCtx);
if(xpathObj == NULL) {
fprintf(stderr,"Error: unable to evaluate xpath expression \"%s\"\n", xpathExpr);
xmlXPathFreeContext(xpathCtx);
return NULL;
}
xmlXPathFreeContext(xpathCtx);
return xpathObj->nodesetval;
}
Note: This function returns all the nodes matching 'nodename'. If you only want the first node, you could replace return xpathObj->nodesetval; by:
if (xpathObj->nodesetval->nodeNr > 0) {
return xpathObj->nodesetval->nodeTab[0];
} else {
return NULL;
}
You could also append [1] to the XPath query to optimize your query.

Resources