diff --git a/ChangeLog b/ChangeLog index 8992b1937..323a727c7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,11 @@ -2012-03-14 Richard Frith-Macdonald & Fred Kiefer +2012-03-12 Fred Kiefer + + * Source/NSXMLPrivate.h: Add comments on owner policy. + * Source/NSXMLNode.m (-XMLStringWithOptions:): Reimplement to + allow closer control over output. + * Source/NSXMLDocument.m (-XMLStringWithOptions:): Remove this method. + +2012-03-14 Richard Frith-Macdonald * Source/NSXMLPrivate.h: * Source/NSXMLNode.m: diff --git a/Source/NSXMLDocument.m b/Source/NSXMLDocument.m index 0e00a30d4..f201af7c1 100644 --- a/Source/NSXMLDocument.m +++ b/Source/NSXMLDocument.m @@ -365,23 +365,6 @@ GS_PRIVATE_INTERNAL(NSXMLDocument) return data; } -- (NSString *) XMLStringWithOptions: (NSUInteger)options -{ - NSString *string = nil; - xmlChar *buf = NULL; - int length; - - xmlDocDumpFormatMemoryEnc(internal->node, &buf, &length, "utf-8", - ((options & NSXMLNodePrettyPrint) ? 1 : 0)); - - if (buf != 0 && length > 0) - { - string = StringFromXMLString(buf, length); - free(buf); - } - return string; -} - - (id) objectByApplyingXSLT: (NSData*)xslt arguments: (NSDictionary*)arguments error: (NSError**)error diff --git a/Source/NSXMLNode.m b/Source/NSXMLNode.m index 1a12dd399..e0e7d6f6e 100644 --- a/Source/NSXMLNode.m +++ b/Source/NSXMLNode.m @@ -904,7 +904,7 @@ execute_xpath(NSXMLNode *xmlNode, NSString *xpath_exp, NSString *nmspaces) - (NSString*) canonicalXMLStringPreservingComments: (BOOL)comments { // FIXME ... generate from libxml - return [self notImplemented: _cmd]; + return [self XMLStringWithOptions: NSXMLNodePreserveWhitespace]; } - (NSXMLNode*) childAtIndex: (NSUInteger)index @@ -1016,6 +1016,7 @@ execute_xpath(NSXMLNode *xmlNode, NSString *xpath_exp, NSString *nmspaces) } [subNodes release]; + [internal->URI release]; [internal->objectValue release]; [internal->subNodes release]; if (node) @@ -1504,20 +1505,32 @@ execute_xpath(NSXMLNode *xmlNode, NSString *xpath_exp, NSString *nmspaces) { NSString *string = nil; xmlChar *buf = NULL; - xmlDocPtr doc; xmlBufferPtr buffer; int error = 0; int len = 0; + xmlSaveCtxtPtr ctxt; + int xmlOptions = 0; - if (internal->node->type == XML_NAMESPACE_DECL) - { - xmlNsPtr ns = (xmlNsPtr)internal->node; - - return StringFromXMLStringPtr(ns->href); - } buffer = xmlBufferCreate(); - doc = internal->node->doc; - error = xmlNodeDump(buffer, doc, internal->node, 1, 1); + + // XML_SAVE_XHTML XML_SAVE_AS_HTML XML_SAVE_NO_DECL XML_SAVE_NO_XHTML + xmlOptions |= XML_SAVE_AS_XML; + if (options & NSXMLNodePreserveWhitespace) + { + xmlOptions |= XML_SAVE_WSNONSIG; + } + if (options & NSXMLNodeCompactEmptyElement) + { + xmlOptions |= XML_SAVE_NO_EMPTY; + } + if (options & NSXMLNodePrettyPrint) + { + xmlOptions |= XML_SAVE_FORMAT; + } + + ctxt = xmlSaveToBuffer(buffer, "utf-8", xmlOptions); + xmlSaveTree(ctxt, internal->node); + error = xmlSaveClose(ctxt); if (-1 == error) { xmlBufferFree(buffer); diff --git a/Source/NSXMLPrivate.h b/Source/NSXMLPrivate.h index 25bb990fb..dc1d8de62 100644 --- a/Source/NSXMLPrivate.h +++ b/Source/NSXMLPrivate.h @@ -86,25 +86,32 @@ StringFromXMLString(const unsigned char *bytes, unsigned length) * * The 'kind' tells us what sort of node this is. * The 'node' points to the underlying libxml2 node structure. - * The 'nsParent' points to the parent node of a namspace structure, needed - * because older (but still used on at least one major linux distribution) - * versions of libxml2 don't have a link to the parent of a namespace. * The 'options' field is a bitmask of options for this node. * The 'objectValue' is the object value set for the node. + * The 'subNodes' array is used to retain the objects pointed to by subnodes. * - * The 'subNodes' array is confusing ... what *is* the ownership policy for - * NSXMLNode with respect to the libxml2 tree? The simple/obvious one would - * be that each NSXMLNode owns any NSXMLNode pointed to by children of the - * corresponding libxml2 structure ... in which case there would be no need - * for this array because the references to the owned NSXMLNode instances - * would be the'_private' fields of the libxml2 structures. + * When we create an Objective-C object for a node we also create objects + * for all parents up to the root object. (Reusing existing once as we find + * them in the _private points of parent nodes) + * This adds the object to the subnode array of the parent object, retaining + * the object in this process. + * This means a document object will retain all the objects we have created + * for its node tree, but we don't have to create all these objects at once. + * When we remove an object from its parent we always call the detach method. + * Here we unlink the libxml2 node and remove the object from its parent's + * subnode array, This will release the object. + * When an object gets deallocated it detaches all the subnodes, releasing + * them in the process and then it frees the node. That way each object takes + * care of freeing its own node, but nodes that don't have objects attached + * to them will get freed when their parent object (e.g. the NSXMLDocument) + * gets deallocated. + * For namespace nodes special rules apply as they don't have a parent pointer. * * URI is probably not needed at all ... I'm not sure */ #define GS_NSXMLNode_IVARS \ NSUInteger kind; \ GS_XMLNODETYPE *node; \ - xmlNodePtr nsParent; \ NSUInteger options; \ id objectValue; \ NSString *URI; \ @@ -193,6 +200,7 @@ StringFromXMLString(const unsigned char *bytes, unsigned length) #include #include #include +#include #include #include