This is a c lib to treat xml as a native database. You can access, modify or replace a node. This is c version of go project- https://github.com/LIJUCHACKO/XmlDB
-
Include Header.
include "xmldb_lib/XmlDB.h"
-
Declare Database.
struct Database *DB=init_Database(0);
-
Load Database.
Load_db(DB,"sample.html");
Content of sample.html
<!DOCTYPE html>
<html>
<head>
<title>This is document title</title>
</head>
<body style="123">
<h1>This is a heading</h1>
<p>Hello World!</p>
</body>
</html>
-
Identifying Nodes using Query.
struct ResultStruct * result= GetNode(DB, 0, "head*/title[This is document title]");
- 'identifiedNodes' contains list of nodes ids(
<head>
) identified under parent node with id '0' (<html> ..</html>
). - '*' marks the node we require.
- [] encloses attribute or value of the node as additional search criteria.
- 'identifiedNodes' contains list of nodes ids(
-
Getting Content of identified nodes.
for(int i=0;i<result->nodeids.length;i++){
printf("\n%s", GetNodeContents(DB, result->nodeids.items[i])->charbuf);
}
Output
<head>
<title>This is document title</title>
</head>
- Getting Value of identified nodes.
result= GetNode(DB, 0, "head/title*");
for(int i=0;i<result->nodeids.length;i++){
printf("\n%s", GetNodeValue(DB, result->nodeids.items[i])->charbuf);
}
Output
This is document title
-
Searching using attribute value.
result = GetNode(DB, 0, "body*[style=\"123\"]/h1");
-
Updating node
printf("\n### Updating node ##\n");
result = GetNode(DB, 0, "head/title");
for(int i=0;i<result->nodeids.length;i++){
struct ResultStruct *newnodes = ReplaceNode(DB, result->nodeids.items[i], "<title>test</title>");
printf("After updation\n");
printf("old node value- %s", GetNodeValue(DB, result->nodeids.items[i])->charbuf); //no output, existing id is removed and new id added
printf("\nnew node value- %s", GetNodeValue(DB, newnodes->nodeids.items[0])->charbuf);
}
printf("\n### Updating node attribute##\n");
result = GetNode(DB, 0, "<x>*[style=\"123\"]/h1");
for(int i=0;i<result->nodeids.length;i++){
printf("\n%s", GetNodeAttribute(DB, result->nodeids.items[i], "style")->charbuf);
UpdateAttributevalue(DB, result->nodeids.items[i], "style", "test2");
printf("\nafter updating Attribute-\n%s", GetNodeContents(DB, result->nodeids.items[i])->charbuf);
UpdateAttributevalue(DB, result->nodeids.items[i], "label", "value");
printf("\nafter adding Attribute-\n%s", GetNodeContents(DB, result->nodeids.items[i])->charbuf);
}
Output
### Updating node ##
After updation
Warning :node doesnot exist
old node value-
new node value- test
### Updating node attribute##
123
after updating Attribute-
<body style="test2">
<h1>This is a heading with style</h1>
<p>Hello World!</p>
</body>
after adding Attribute-
<body style="test2" label="value">
<h1>This is a heading with style</h1>
<p>Hello World!</p>
</body>
-
Recursive search.
result = GetNode(DB, 0, "../h1");
-
List Functions to be used to free the return pointers.
Memory deallocation function | Deallocates Return type | Functions that return the structure |
---|---|---|
free_StringReturn() | struct String | GetNodeName() |
" | " | GetNodeContents() |
" | " | GetNodeValue() |
" | " | GetNodeAttribute() |
free_ResultStruct() | struct ResultStruct | GetNode() |
" | " | UpdateNodevalue() |
" | " | UpdateAttributevalue() |
" | " | ReplaceNode() |
" | " | InserSubNode() |
" | " | AppendBeforeNode() |
" | " | AppendAfterNode() |
free_VectorIntReturn() | struct VectorInt | RemoveNode() |
" | " | ChildNodes() |
-Last but not the least don't forget to free Database pointer.
'free(DB)'
-I have not used memory dealocation functions in the example inorder to keep the example simple.
<!DOCTYPE html>
<html>
<head><title>This is document title</title></head>
<body style="123">
<h1>This is a heading</h1>
<p>Hello World!</p>
</body>
</html>
global_dbLines | global_ids | global_paths | global_values | global_attributes |
---|---|---|---|---|
<!DOCTYPE html> |
-1 | |||
<head> |
0 | /head | ||
<title>This is document title</title> |
1 | /head/title | This is document title | |
<\head> |
2 | /head/~ | ||
<body style="123" font="arial"> |
3 | /body | style="123"|| font="arial" | |
<h1>This is a heading</h1> |
4 | /body/h1 | ||
<p>Hello World!</p> |
5 | /body/p | This is a heading | |
</body> |
6 | /body/~ | Hello World! | |
Note:- If a new node is inserted in between, global_id '7' will be assigned to it. global_id will be unique and will be retained till the node is deleted.
index/global_id | nodeNoToLineno[index] |
---|---|
0 | 1 |
1 | 2 |
2 | 3 |
3 | 4 |
index/global_id | Nodeendlookup[index] |
---|---|
0 | 2 |
1 | 1 |
2 | 2 |
3 | 6 |
4 | 4 |
5 | 5 |
-Say the path is '/head/title' then hash is calculated for 'title'.
-Corresponding to the hash value a list of global_ids ,arranged in the increasing order of lineno, is stored.
Hash no | global id list corresponding to the hash |
---|---|
0 | |
1 | |
2 | [id1,id2,id3,id4] |
-Binary search is utilised to find ids, under a parent node, from this list.