In the previous article we saw how to add a new XML node. Here we’ll see how to delete an an XML node from a file. We’ll use the same example XML file.
<?xml version="1.0"?>
<catalog>
<book id="bk101">
<author>Gambardella, Matthew</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>44.95</price>
<publish_date>2000-10-01</publish_date>
<description>An in-depth look at creating applications
with XML.</description>
</book>
<book id="bk102">
<author>Ralls, Kim</author>
<title>Midnight Rain</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2000-12-16</publish_date>
<description>A former architect battles corporate zombies,
an evil sorceress, and her own childhood to become queen
of the world.</description>
</book>
<book id="bk103">
<author>Corets, Eva</author>
<title>Maeve Ascendant</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2000-11-17</publish_date>
<description>After the collapse of a nanotechnology
society in England, the young survivors lay the
foundation for a new society.</description>
</book>
</catalog>
In this example, we have 3 ‘book‘ nodes under ‘catalog‘. We’ll write a C program to delete one of them.
Program to Delete XML Node
#include <stdio.h>
#include <libxml/parser.h>
/*gcc `xml2-config --cflags --libs` test.c*/
xmlNode * find_node(xmlNode * node, char * book_id) {
xmlNode * result;
if (node == NULL) return NULL;
while(node) {
if((node->type == XML_ELEMENT_NODE)
&& (strcmp(node->name, "book") == 0)
&& (strcmp(xmlGetProp(node, "id"), book_id) == 0)) {
return node;
}
if (result = find_node(node->children, book_id)) return result;
node = node->next;
}
return NULL;
}
void delete_node(xmlNode *root, char* book_id) {
xmlNode* node = find_node(root, book_id);
if(node == NULL) {
printf("Book with id %s not found\n", book_id);
return;
}
xmlUnlinkNode(node);
xmlFreeNode(node);
}
void save_to_file(xmlDoc *doc, char *file_name) {
xmlChar *xmlbuff;
int buffersize;
FILE *fp;
xmlDocDumpFormatMemory(doc, &xmlbuff, &buffersize, 1);
fp = fopen(file_name, "w+");
fprintf(fp, xmlbuff);
fclose(fp);
}
int main(){
xmlDoc *doc = NULL;
xmlNode *root_element = NULL;
doc = xmlReadFile("input.xml", NULL, 0);
if (doc == NULL) {
printf("Could not parse the XML file.\n");
return 1;
}
root_element = xmlDocGetRootElement(doc);
delete_node(root_element, "bk102");
save_to_file(doc, "output.xml");
xmlFreeDoc(doc);
xmlCleanupParser();
return 0;
}
This program has the following important functions.
find_node(): It finds a ‘book‘ node based on a book id. It traverses the XML doc and returns a node whose node name is ‘book‘ and the ‘id‘ property of that node is equal to the input book id.
delete_node(): It takes a book id as input and deletes the book node with this book id. It first finds the node by calling the find_node() function. Then it detaches that node from the XML doc by calling xmlUnlinkNode() function. After that it frees the detached node using xmlFreeNode() to void memory leak.
save_to_file(): Saves the XML doc into a file.
In the main() function, we first read the “input.xml” file. So this ‘input.xml‘ files needs to be present in time of running the program in the same directory. Then we called the delete_node() function to delete the second book entry. That’s why we passed ‘bk102‘ book id as input. After deleting the node, we saved the XML content to ‘output.xml‘ file.
To compile this program, run this command.
gcc `xml2-config --cflags --libs` test.c -o test
It requires libxml2 development package. If it is not already installed, then you can follow this article to install that first.
If you run this program (./test), the ‘output.txt‘ will get generated in the same directory. The ‘output.txt‘ will not have the second book entry.
the instructions
xmlUnlinkNode(node);
xmlFreeNode(node);
leave a blank line in the output file, is there a way to avoid that or to clean the blank line