[xml] A generic way to add user data to nodes?



Hi, everybody

I feel that it would be useful if libxml had a generic way to add user data
to nodes. Right no fighting over the _private field or using external 
lookup tables seems to be the only options.

Using the content field to store line numbers also seems a bit awkward.

This is my suggestion how a solution might look:

<skeleton-code>
typedef struct _xmlNodeData xmlNodeData;
typedef xmlNodeData *xmlNodeDataPtr;

/* All user data must have this struct as its first field. */
struct _xmlNodeData {
    xmlNodeDataClassPtr node_data_class; /* Identifies the type of this
                                             object.*/
    xmlNodeDataPtr next; /* Points to next userdata object or NULL if none. */
    xmlNodeDataPtr *prevp; /* Points to the next pointer of the previous object.
                              Makes it possible to unlink data quickly.
                              Not really necessary but convenient. */
    xmlNode *node; /* Could replace the previous field, but less efficient. */
};


typedef struct _xmlNodeDataClass xmlNodeDataClass;
typedef xmlNodeDataClass *xmlNodeDataPtrClass;

typdef void (*xmlNodeDataReleaseMethod)(xmlNodeDataPtr data);
typdef void (*xmlNodeDataCopyMethod)(xmlNodeDataPtr data, xmlNodePtr copy_to);

/* Usually stored as a compile time constant. */
struct _xmlNodeDataClass {
    const char *class_name;  /* Useful for debugging. */
    xmlNodePtr super; /* Super class. Enables inheritance. Might be overkill.*/
    xmlNodeDataReleaseMethod release; /* Called when the node is destroyed 
                                         or for some other reason doesn't need
                                         the user data. */
    xmlNodeDataCopyMethod copy; /* Called when a node is copied. */
};

/* Add another user data object to a node. 
   To maintain backward comptibility the _private field of any node is not
   touched until the application has called this function at least once . */
void            xmlNodeDataAdd          (xmlNodeDataPtr data,
                                         xmlNodePtr node);

/* Unlink an object from a node. The release method is not called. */
void            xmlNodeDataUnlink       (xmlNodePtr data);

/* Find the first node with the given class that's attached to this node,
   or NULL if none. Will using the class pointer as a key work on all
   platforms? */
   
xmlNodeDataPtr  xmlNodeDataFind         (xmlNodePtr node,
                                         xmlNodeDataClassPtr data_class);
</skeleton-code>


The _private field is used to point to the first user data object.

The xmlNew* functions would have to be changed to initialize _private
to NULL.

xmlFreeNode needs to call the release method on all attached user
data objects. Should the release callback be called on all super classes too,
like a C++ destructor?

xmlCopyNode should call the copy method on all attached data.

There are probably other functions that need modification too.

How does this work with threads?

What do you think? Is this a good idea? In the long run it would
require to rewrite some amounts of code, but I still think this kind
of solution is the way to go.

simon



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]