From e70154923fe970a67502cb763ba5af9166cd3752 Mon Sep 17 00:00:00 2001 From: Adrien Bourmault Date: Sun, 31 Mar 2024 22:04:00 +0200 Subject: [PATCH] src/model.c: support node copying and changing attribute (e.g. ID) on the fly --- src/model.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 7 deletions(-) diff --git a/src/model.c b/src/model.c index 6e68723..df47a08 100644 --- a/src/model.c +++ b/src/model.c @@ -38,6 +38,8 @@ struct model_t *knownModels = NULL; +static xmlHashTablePtr hashTable == NULL; + /* -------------------------------------------------------------------------- */ /** @@ -48,11 +50,12 @@ struct model_t *knownModels = NULL; * @param currentPath The path to the current node. */ void model_populate_hashtable (xmlNode *node, - xmlHashTablePtr hashTable, char *currentPath) { if (node == NULL) return; + assert(hashTable == NULL); + // Skip text nodes and others that are not element nodes if (node->type != XML_ELEMENT_NODE) { model_populate_hashtable(node->next, hashTable, currentPath); @@ -86,6 +89,8 @@ void model_populate_hashtable (xmlNode *node, */ char* model_find_node_by_path (xmlNode *node, const char *path) { + assert(hashTable != NULL); + return (xmlNodePtr)xmlHashLookup(hashTable, (const xmlChar *)path); } @@ -97,10 +102,11 @@ char* model_find_node_by_path (xmlNode *node, const char *path) * @param newContent The new content to set for the node. * @return 1 if the node was found and modified, 0 otherwise. */ -int model_modify_node (xmlHashTablePtr hashTable, - const char *path, +int model_modify_node (const char *path, const char *newContent) { + assert(hashTable != NULL); + xmlNodePtr node = model_find_node_by_path(hashTable, path); if (node) { // Free the current content of the node, if any @@ -120,10 +126,11 @@ int model_modify_node (xmlHashTablePtr hashTable, * @param attributeName The name of the attribute. * @return The value of the attribute, or NULL if not found. */ -char* model_get_attribute (xmlHashTablePtr hashTable, - const char* nodePath, +char* model_get_attribute (const char* nodePath, const char* attributeName) { + assert(hashTable != NULL); + xmlNodePtr node = (xmlNodePtr)xmlHashLookup(hashTable, (const xmlChar*)nodePath); if (node) { return getAttributeValue(node, attributeName); @@ -141,11 +148,12 @@ char* model_get_attribute (xmlHashTablePtr hashTable, * @param attributeValue The value to set for the attribute. * @return 1 on success, 0 on failure. */ -int model_set_attribute (xmlHashTablePtr hashTable, - const char* nodePath, +int model_set_attribute (const char* nodePath, const char* attributeName, const char* attributeValue) { + assert(hashTable != NULL); + xmlNodePtr node = (xmlNodePtr)xmlHashLookup(hashTable, (const xmlChar*)nodePath); if (node) { return setAttributeValue(node, attributeName, attributeValue); @@ -154,6 +162,46 @@ int model_set_attribute (xmlHashTablePtr hashTable, } } +/** + * Copies a node recursively to a new sibling node with a modified attribute and updates the hashtable. + * + * @param doc The document to which the nodes belong. + * @param node The node to copy. + * @param hashTable The hashtable for tracking nodes by path. + * @param originalNodePath The path of the original node in the hashtable. + * @param attributeName The name of the attribute to modify in the copied node. + * @param newAttributeValue The new value for the specified attribute in the copied node. + * @return The copied node with the modified attribute, or NULL on failure. + */ +xmlNodePtr model_copy_node(struct model_t *self, + xmlNodePtr node, + const char* originalNodePath, + const char* attributeName, + const char* newAttributeValue) +{ + assert(hashTable != NULL); + + // Deep copy the node + xmlNodePtr copiedNode = xmlDocCopyNode(node, self->doc, 1); + if (copiedNode == NULL) { + return NULL; // Failed to copy + } + + // Modify the specified attribute in the copied node + xmlSetProp(copiedNode, (const xmlChar*)attributeName, (const xmlChar*)newAttributeValue); + + // Insert the copied node as the next sibling of the original node + xmlAddNextSibling(node, copiedNode); + + // Calculate the new node's path. + char newPath[1024]; + snprintf(newPath, sizeof(newPath), "%s_copy", originalNodePath); + + // Update the hashtable with the new node's path + xmlHashAddEntry(hashTable, (const xmlChar*)newPath, copiedNode); + + return copiedNode; +} /* -------------------------------------------------------------------------- */ char model_get_dim (struct model_t *self)