2

I try to write a C++ wrapper to a well-known C library, libxml2. In libxml2, an xmlDocPtr represent an XML document and xmlNodePtr represents a node. An xmlDocPtr contains a root xmlNodePtr and every xmlNodePtr can have a child xmlNodePtr. Only xmlDocPtr must be freed, when it is needed - it automatically frees all XML nodes that belongs to it. However, independent xmlNodePtrs must be freed before they get added to a xmlDocPtr or as a child to another xmlNodePtr.

Here is a C example for usage: http://www.xmlsoft.org/examples/tree2.c

I made a wrapper interface to xmlDocPtr (this represents a XML document - i call it XMLDocument) and another one for xmlNodePtr (this represents a XML node inside an XML document - I call it XMLNode). What is the better approach in your opinion to create an XMLNode in an XMLDocument (or a child XML node in a node)?

  1. Create an XMLNode by itself and set its attributes, namespaces, child nodes, etc. If it is done, add this XMLNode to the XMLDocument (or to a parent XMLNode). Before adding the node, we own its resource, but after adding, we must not free its pointer. We should do the pointer adding and the ownership handling in an atomic way. We should also handle the fact, that we can't add an already added node again the another node/doc (to avoid double free). But we can modify the node's properties after the adding, if we want.
  2. Create an XMLNode by itself and set its attributes, namespaces, child nodes, etc. If it is done, add this XMLNode to the XMLDocument (or to a parent XMLNode). Before adding the node, we own its resource, but after adding, we must not free its pointer. We can deep copy the resource from XMLNode (xmlCopyNode) or grab XMLNode-s resource with std::move, or do something similar. After the addition, this XMLNode cannot be updated or used for any purpose, or be added again to another node/document.
  3. Call a function in XMLDocument that creates an XMLNode an passes it back to us (same for XMLNode child creation). This XMLNode never owns the resource. We can use XMLNode after the creation and add namespace, attributes, child nodes to it. There is no "addition to parent", only "creation from parent".
4
  • 1
    Do you have any particular motivation for using libxml2 rather than one of the other C++ XML parser libraries. Any wrapper should really depend on your specific use-case, otherwise it may simply end up negating any of the reasons for using libxml2 in the first place. Some of the other XML libraries already have much simpler APIs, which are more idiomatic for C++. (Also see: stackoverflow.com/questions/9387610/…) Commented Jun 28 at 18:42
  • Unless you have a specific use case in mind, simply wrap the C structs into C++ classes and then add the C functions which take one such struct as parameter and make them methods inside the class. Functions that alloc memory become ctors, functions that free memory become destructors
    – Ccm
    Commented Jun 28 at 22:19
  • @BenCottrell Yeah, this is a big product in which this library is already used. The cost of replacing libxml2 will be much more bigger. Commented Jul 1 at 7:03
  • @ZoltánVárnagy in which case I recommend a completely different goal -- don't just aim to write a wrapper for Libxml2, as you can really do a lot better than that; having that legacy code in front of you means that you have a large repository of existing use-cases and usage patterns at your disposal. Instead of focusing on Libxml2 (whose own structure may or may not be all that useful to the problem at hand), take time analysing the legacy code's XML use-cases, identify patterns and look for ways to isolate and generalise those use cases, including ways to unit test those use-cases. Commented Jul 1 at 12:37

1 Answer 1

4

#1 sounds good, your XMLNode just needs to distinguish between the cases where the node is in an XMLDocument, or not (_xmlNode struct has a doc field, I looked it up). When it is, don't free the node pointer resource in the destructor, and throw an exception when someone tries to add such an XMLNode to another XMLDocument.

You can implement #3 additionally, this is not mutual exclusive.

#2 (making deep copies, and keeping the XMLNode as a read-only copy after it was added to an XMLDocument) does not make much sense to me. Don't forget, creation of an XMLDocument is not the only use case, but also traversal of the tree, for which you need references to nodes inside an XMLDocument either. This will not mix well with this design.

I think most important is that you implement a few example or real world cases with your library, to find out if the API works well for you. That should give you feedback way more useful than anything strangers from the internet can provide from this 10000 feet view.

1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.