I'm working on an XML-to-model-object serialization and deserialization library. There are three main design goals for the code:It should parse XML into and serialize from Cocoa-native collection objects such as NSDictionary, NSArray and NSString. Creating a custom representation (e.g. XMLNode classes) should be avoided. This is mainly done in order to embrace the philosophy of JSON whereby the parser is able to perform a simple mapping from the string representation to a tree made out of the most common data types.XML is a very verbose format in that it has many ways of expressing the contains or is child of relation. E.g., unlike in JSON, both attributes and contained text nodes can but need not express the same semantics. Therefore, in order to preserve all the potential information in the original XML structure, we need to define a canonical representation for its syntax tree instead of just trying to be smart and somehow make sense of it in general. The format I've come up with is an NSDictionary for each node, where the type of the node (e.g. element, text, comment, etc.) is registered, and depending on this type, the children, attributes, etc. thereof are also stored in a collection object.However, the resulting tree is way too verbose to be either human- or easily machine-readable in the sense of being able to simply and immediately map it onto business logic model objects. So, the idea is to introduce two layers of transformations or mappings. One of them takes the canonical (hence very regular) but verbose tree and transforms it into a more compact and readable representation which the user can interpret using semantics specific to their concrete use case. This, for one, gives them an opportunity to use already-existing object mapping libraries to generate model object from the collection-based tree. The other layer of transformations performs the inverse operation, whereby a simple collection-based structure is generated from business objects, and the transforms morph it into the canonical format from which textual XML can be generated.To meet these goals, I've wrapped the libxml2 library in my Objective-C code, and used mostly functional style to implement the transforms (which are basically a map of various functions and their composition over the tree nodes).The problem with the quality of my code is two-fold. My first concern is that I have several long methods. I like to have my functions fit in one screen (which is 25 lines for me - no jokes!), but here is, for example, my serialization (tree-to-XML-text) method which is over 80 lines long!+ (xmlChar *_Nullable)bufferWithDictionary:(NSDictionary *)dictionary                               indentation:(NSString *_Nullable)indentation                                    length:(NSUInteger *)length                                     error:(NSError *__autoreleasing *)error {    NSParameterAssert(dictionary);    NSParameterAssert(length);    *length = 0;    if (error) {        *error = nil;    }    //    // Initialize buffer and writer    // (this is gonna be long)    //    xmlBuffer *buf = xmlBufferCreate();    if (buf == NULL) {        if (error) {            *error = [NSError SCIXMLErrorWithCode:SCIXMLErrorCodeWriterInit                                           format:@could not allocate buffer];        }        return NULL;    }    xmlTextWriter *writer = xmlNewTextWriterMemory(buf, NO);    if (writer == NULL) {        if (error) {            *error = [NSError SCIXMLErrorWithCode:SCIXMLErrorCodeWriterInit                                           format:@could not allocate writer];        }        xmlBufferFree(buf);        return NULL;    }    // If the user wants indentation, try setting it up.    if (        indentation        &&        (            xmlTextWriterSetIndent(writer, 1) < 0            ||            xmlTextWriterSetIndentString(writer, XS(indentation.UTF8String)) < 0        )    ) {        if (error) {            *error = [NSError SCIXMLErrorWithCode:SCIXMLErrorCodeWriterInit                                           format:@could not set indentation];        }        xmlFreeTextWriter(writer);        xmlBufferFree(buf);        return NULL;    }    // Start writing the document (which is not just the same as the root node!)    if (xmlTextWriterStartDocument(writer, NULL, UTF-8, NULL) < 0) {        if (error) {            *error = [NSError SCIXMLErrorWithCode:SCIXMLErrorCodeWriterInit                                           format:@could not start writing document];        }        xmlFreeTextWriter(writer);        xmlBufferFree(buf);        return NULL;    }    // Try writing root element.    // Move content out of buffer upon success.    xmlChar *content = NULL;    if ([self writeXMLNode:dictionary writer:writer error:error]) {        // If writing the root element succeeded, try closing the document.        if (xmlTextWriterEndDocument(writer) >= 0) {            *length = xmlBufferLength(buf);            content = xmlBufferDetach(buf);        } else if (error) {            *error = [NSError SCIXMLErrorWithCode:SCIXMLErrorCodeWriteFailed                                           format:@error writing XML for node %p, (void *)dictionary];        }    }    // Clean up writer state    xmlFreeTextWriter(writer);    xmlBufferFree(buf);    return content;}I've tried refactoring it into smaller functions, but oddly, I felt that it would actually reduce readability, and I also found some parts hard to factor out well, because early returns are needed for error handling (and unless I'm willing to pollute my API with setjmp(), which I am not, I can't just return to two call stack frames above the currently executing function). Do you have any advice, a technique, etc. that could be applied to this method (and potentially more of them, given that the cause of these problems, I feel, is similar throughout the code)?My second problem is way less specific - despite the fact that a colleague of mine and I spent several days coming up with the overall idea and with designing the details of the API, I just have a gut feeling that the code I've written is ad-hoc. It might not come through too well based on one single method, but I'm starting to think that I've written way more code than I should have for such a simple task. Even when my methods are not too long and not at all repetitive, I'm concerned with how many smaller or bigger internal helper methods I've created, how many properties I added to system classes through categories, and the like. How could I remedy that?
Functional-style Cocoa XML serializer and object mapper
parsing;error handling;objective c;xml