I am using Libxml2 for encoding the data in a xml file. My data contain tags like "<" and ">". when it is converted into xml these tags are also converted into "<" and ">". Is there any way to solve this problem. I want to use those tags as xml nodes while decoding that xml file, so CDATA is not a solution for this problem. Please give any solution for this. Thanks.
Example Code:
xmlNewChild(node, NULL, (xmlChar *)"ADDRESS", (xmlChar *)"<street>Park Street</street><city>kolkata</city>");
and output of above code is:
<person>
<ADDRESS><street>Park Street</street><city>Kolkata</city></ADDRESS>
If you want a string to be treated as xml, then you should parse it and obtain xmlDoc
from it, using xmlReadMemory. It could be usable for larger strings, but usually the document is builded using single step instructions, like in Joachim's answer. Here I present xmlAddChildFromString
function to do the stuff in a string way.
#include <stdio.h>
#include <string.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
/// Returns 0 on failure, 1 otherwise
int xmlAddChildFromString(xmlNodePtr parent, xmlChar *newNodeStr)
{
int rv = 0;
xmlChar *newNodeStrWrapped = calloc(strlen(newNodeStr) + 10, 1);
if (!newNodeStrWrapped) return 0;
strcat(newNodeStrWrapped, "<a>");
strcat(newNodeStrWrapped, newNodeStr);
strcat(newNodeStrWrapped, "</a>");
xmlDocPtr newDoc = xmlReadMemory(
newNodeStrWrapped, strlen(newNodeStrWrapped),
NULL, NULL, 0);
free(newNodeStrWrapped);
if (!newDoc) return 0;
xmlNodePtr newNode = xmlDocCopyNode(
xmlDocGetRootElement(newDoc),
parent->doc,
1);
xmlFreeDoc(newDoc);
if (!newNode) return 0;
xmlNodePtr addedNode = xmlAddChildList(parent, newNode->children);
if (!addedNode) {
xmlFreeNode(newNode);
return 0;
}
newNode->children = NULL; // Thanks to milaniez
newNode->last = NULL; // for fixing
xmlFreeNode(newNode); // the memory leak.
return 1;
}
int
main(int argc, char **argv)
{
xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
xmlNodePtr root = xmlNewNode(NULL, BAD_CAST "root");
xmlDocSetRootElement(doc, root);
xmlAddChildFromString(root,
"<street>Park Street</street><city>kolkata</city>");
xmlDocDump(stdout, doc);
xmlFreeDoc(doc);
return(0);
}
You have to call xmlNewChild
in a chain, one call for the parent node and a call each for each sub-node:
xmlNodePtr *addressNode = xmlNewChild(node, NULL, (xmlChar *) "address", NULL);
xmlNewChild(addressNode, NULL, (xmlChar *) "street", "Park Street");
xmlNewChild(addressNode, NULL, (xmlChar *) "city", "Koltaka");
You can try to use function xmlParseInNodeContext. It allows you to parse raw XML in the context of parent node, and constructs a node that can be attached to the parent.
For example:
const char * xml = "<a><b><c>blah</c></b></a>";
xmlNodePtr new_node = NULL;
// we assume that 'parent' node is already defined
xmlParseInNodeContext(parent, xml, strlen(xml), 0, &new_node);
if (new_node) xmlAddChild(parent, new_node);
I'm now using the following code to inject XML text (possibly containing multiple elements) into an existing node (thanks to Nazar and nwellnhof for the one answer and referring me from my question (Injecting a string into an XML node without content escaping) to this one):
std::string xml = "<a>" + str + "</a>";
xmlNodePtr pNewNode = nullptr;
xmlParseInNodeContext(pParentNode, xml.c_str(), (int)xml.length(), 0, &pNewNode);
if (pNewNode != nullptr)
{
// add new xml node children to parent
xmlNode *pChild = pNewNode->children;
while (pChild != nullptr)
{
xmlAddChild(pParentNode, xmlCopyNode(pChild, 1));
pChild = pChild->next;
}
xmlFreeNode(pNewNode);
}
It takes the string (str) adds a surrounding element (< a >...< a/ >), parses the string using xmlParseInNodeContext and then adds the children of the new node to the parent. It is important to add the children of the new node and not the new node to avoid having < a >...< a/ > in the final XML.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With