diff --git a/src/build/common/xml.c b/src/build/common/xml.c index b5ad1198e..56b239b6e 100644 --- a/src/build/common/xml.c +++ b/src/build/common/xml.c @@ -4,6 +4,31 @@ XML Handler Extensions // Include core module #include "common/type/xml.c" +#include "build/common/xml.h" + +/**********************************************************************************************************************************/ +XmlDocument * +xmlDocumentNewParam(const String *const rootNode, const XmlDocumentNewParam param) +{ + FUNCTION_TEST_BEGIN(); + FUNCTION_TEST_PARAM(STRING, rootNode); + FUNCTION_TEST_PARAM(STRING, param.dtdName); + FUNCTION_TEST_PARAM(STRING, param.dtdFile); + FUNCTION_TEST_END(); + + ASSERT(rootNode != NULL); + + XmlDocument *const result = xmlDocumentNew(rootNode); + + if (param.dtdName != NULL) + { + ASSERT(param.dtdFile != NULL); + xmlCreateIntSubset(result->xml, (unsigned char *)strZ(param.dtdName), NULL, (unsigned char *)strZ(param.dtdFile)); + } + + FUNCTION_TEST_RETURN(XML_DOCUMENT, result); +} + /**********************************************************************************************************************************/ String * xmlNodeAttribute(const XmlNode *this, const String *name) @@ -27,3 +52,74 @@ xmlNodeAttribute(const XmlNode *this, const String *name) FUNCTION_TEST_RETURN(STRING, result); } + +/**********************************************************************************************************************************/ +void +xmlNodeAttributeSet(XmlNode *const this, const String *const name, const String *const value) +{ + FUNCTION_TEST_BEGIN(); + FUNCTION_TEST_PARAM(XML_NODE, this); + FUNCTION_TEST_PARAM(STRING, name); + FUNCTION_TEST_PARAM(STRING, value); + FUNCTION_TEST_END(); + + ASSERT(this != NULL); + ASSERT(name != NULL); + ASSERT(value != NULL); + + xmlSetProp(this->node, (unsigned char *)strZ(name), (unsigned char *)strZ(value)); + + FUNCTION_TEST_RETURN_VOID(); +} + +/**********************************************************************************************************************************/ +void +xmlNodeChildAdd(XmlNode *const this, const XmlNode *const child) +{ + FUNCTION_TEST_BEGIN(); + FUNCTION_TEST_PARAM(XML_NODE, this); + FUNCTION_TEST_PARAM(XML_NODE, child); + FUNCTION_TEST_END(); + + ASSERT(this != NULL); + ASSERT(child != NULL); + + MEM_CONTEXT_TEMP_BEGIN() + { + for (xmlNodePtr currentNodeRaw = child->node->children; currentNodeRaw != NULL; currentNodeRaw = currentNodeRaw->next) + { + // Skip comments + if (currentNodeRaw->type == XML_COMMENT_NODE) + continue; + + // Copy all child nodes (only node and text types are copied) + XmlNode *const currentNode = xmlNodeNew(currentNodeRaw); + + if (currentNode->node->type == XML_ELEMENT_NODE) + { + XmlNode *const node = xmlNodeAdd(this, STR((char *)currentNode->node->name)); + + // Copy node attributes + for (xmlAttrPtr currentAttr = currentNode->node->properties; currentAttr != NULL; currentAttr = currentAttr->next) + { + xmlNodeAttributeSet( + node, STR((char *)currentAttr->name), xmlNodeAttribute(currentNode, STR((char *)currentAttr->name))); + } + + // Recurse to copy child nodes + xmlNodeChildAdd(node, currentNode); + } + else + { + CHECK_FMT( + AssertError, currentNode->node->type == XML_TEXT_NODE, "unknown type %u in node '%s'", currentNode->node->type, + (char *)currentNode->node->name); + + xmlNodeContentSet(this, xmlNodeContent(currentNode)); + } + } + } + MEM_CONTEXT_TEMP_END(); + + FUNCTION_TEST_RETURN_VOID(); +} diff --git a/src/build/common/xml.h b/src/build/common/xml.h index 6da781333..4ed66da23 100644 --- a/src/build/common/xml.h +++ b/src/build/common/xml.h @@ -6,10 +6,32 @@ XML Handler Extensions #include "common/type/xml.h" +/*********************************************************************************************************************************** +Constructors +***********************************************************************************************************************************/ +typedef struct XmlDocumentNewParam +{ + VAR_PARAM_HEADER; + const String *dtdName; // DTD name, if any + const String *dtdFile; // DTD file (must be set if dtdName is set) +} XmlDocumentNewParam; + +#define xmlDocumentNewP(rootNode, ...) \ + xmlDocumentNewParam(rootNode, (XmlDocumentNewParam){VAR_PARAM_INIT, __VA_ARGS__}) + +XmlDocument *xmlDocumentNewParam(const String *rootNode, XmlDocumentNewParam param); + /*********************************************************************************************************************************** Node Getters/Setters ***********************************************************************************************************************************/ -// Node attribute +// Get/set node attribute String *xmlNodeAttribute(const XmlNode *this, const String *name); +void xmlNodeAttributeSet(XmlNode *this, const String *name, const String *value); + +/*********************************************************************************************************************************** +Functions +***********************************************************************************************************************************/ +// Add all child nodes to another node +void xmlNodeChildAdd(XmlNode *this, const XmlNode *child); #endif diff --git a/test/src/module/common/typeXmlTest.c b/test/src/module/common/typeXmlTest.c index 679aed1bc..adc29e37d 100644 --- a/test/src/module/common/typeXmlTest.c +++ b/test/src/module/common/typeXmlTest.c @@ -84,7 +84,7 @@ testRun(void) // Create an empty document, add data to it, and output xml // ------------------------------------------------------------------------------------------------------------------------- - TEST_ASSIGN(xmlDocument, xmlDocumentNew(STRDEF("CompleteMultipartUpload")), "new xml with root node"); + TEST_ASSIGN(xmlDocument, xmlDocumentNewP(STRDEF("CompleteMultipartUpload")), "new xml with root node"); XmlNode *partNode = NULL; TEST_ASSIGN(partNode, xmlNodeAdd(xmlDocumentRoot(xmlDocument), STRDEF("Part")), "create part node 1"); @@ -103,6 +103,38 @@ testRun(void) "2E2" "\n", "get xml"); + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("copy xml between documents"); + + XmlDocument *xmlDocument2 = NULL; + + TEST_ASSIGN( + xmlDocument, xmlDocumentNewP(STRDEF("doc1"), .dtdName = STRDEF("doc"), .dtdFile = STRDEF("doc.dtd")), + "new xml with dtd"); + TEST_ASSIGN( + xmlDocument2, + xmlDocumentNewBuf( + BUFSTRDEF( + "\n" + "\n" + " \n" + " text55\n" + " name55\n" + "")), + "valid xml"); + + TEST_RESULT_VOID(xmlNodeChildAdd(xmlDocumentRoot(xmlDocument), xmlDocumentRoot(xmlDocument2)), "copy xml"); + TEST_RESULT_STR_Z( + strNewBuf(xmlDocumentBuf(xmlDocument)), + "\n" + "\n" + "\n" + " \n" + " text55\n" + " name55\n" + "\n", + "get xml"); } FUNCTION_HARNESS_RETURN_VOID();