mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
* Source/NSXMLDocument.m (-URI, -setURI:): Specific implementation.
* Source/NSXMLPrivate.h: Remove URI ivar. * Source/NSXMLElement.m, * Source/NSXMLNode.m: Full support for namespaces. * Tests/base/NSXMLNode/namespace.m: Test code borrowed from Google data project. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@34972 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
818d2ee2ae
commit
2079071716
6 changed files with 517 additions and 79 deletions
|
@ -1,3 +1,12 @@
|
|||
2012-03-22 Fred Kiefer <FredKiefer@gmx.de>
|
||||
|
||||
* Source/NSXMLDocument.m (-URI, -setURI:): Specific implementation.
|
||||
* Source/NSXMLPrivate.h: Remove URI ivar.
|
||||
* Source/NSXMLElement.m,
|
||||
* Source/NSXMLNode.m: Full support for namespaces.
|
||||
* Tests/base/NSXMLNode/namespace.m: Test code borrowed from Google
|
||||
data project.
|
||||
|
||||
2012-03-21 Fred Kiefer <FredKiefer@gmx.de>
|
||||
|
||||
* Source/NSXMLDocument.m: Correct memory management.
|
||||
|
|
|
@ -280,15 +280,42 @@ GS_PRIVATE_INTERNAL(NSXMLDocument)
|
|||
internal->node->standalone = standalone;
|
||||
}
|
||||
|
||||
- (void) setURI: (NSString*)URI
|
||||
{
|
||||
xmlDocPtr node = internal->node;
|
||||
|
||||
if (node->URL != NULL)
|
||||
{
|
||||
xmlFree((xmlChar *)node->URL);
|
||||
}
|
||||
node->URL = XMLStringCopy(URI);
|
||||
}
|
||||
|
||||
- (NSString*) URI
|
||||
{
|
||||
xmlDocPtr node = internal->node;
|
||||
|
||||
if (node->URL)
|
||||
{
|
||||
return StringFromXMLStringPtr(node->URL);
|
||||
}
|
||||
else
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void) setVersion: (NSString*)version
|
||||
{
|
||||
if ([version isEqualToString: @"1.0"] || [version isEqualToString: @"1.1"])
|
||||
{
|
||||
if (internal->node->version != NULL)
|
||||
xmlDocPtr node = internal->node;
|
||||
|
||||
if (node->version != NULL)
|
||||
{
|
||||
xmlFree((xmlChar *)internal->node->version);
|
||||
xmlFree((xmlChar *)node->version);
|
||||
}
|
||||
internal->node->version = XMLStringCopy(version);
|
||||
node->version = XMLStringCopy(version);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -299,8 +326,10 @@ GS_PRIVATE_INTERNAL(NSXMLDocument)
|
|||
|
||||
- (NSString*) version
|
||||
{
|
||||
if (internal->node->version)
|
||||
return StringFromXMLStringPtr(internal->node->version);
|
||||
xmlDocPtr node = internal->node;
|
||||
|
||||
if (node->version)
|
||||
return StringFromXMLStringPtr(node->version);
|
||||
else
|
||||
return @"1.0";
|
||||
}
|
||||
|
|
|
@ -33,6 +33,44 @@
|
|||
#import "GSInternal.h"
|
||||
GS_PRIVATE_INTERNAL(NSXMLElement)
|
||||
|
||||
void
|
||||
cleanup_namespaces(xmlNodePtr node, xmlNsPtr ns)
|
||||
{
|
||||
if ((node == NULL) || (ns == NULL))
|
||||
return;
|
||||
|
||||
if ((node->type == XML_ATTRIBUTE_NODE) ||
|
||||
(node->type == XML_ELEMENT_NODE))
|
||||
{
|
||||
xmlNsPtr ns1 = node->ns;
|
||||
|
||||
if (ns1 == ns)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Either both the same or one NULL and the other the same
|
||||
if (ns1 != NULL &&
|
||||
(((ns1->href == NULL) &&
|
||||
(xmlStrcmp(ns1->prefix, ns->prefix) == 0)) ||
|
||||
((ns1->prefix == NULL) &&
|
||||
(xmlStrcmp(ns1->href, ns->href) == 0)) ||
|
||||
((xmlStrcmp(ns1->prefix, ns->prefix) == 0) &&
|
||||
(xmlStrcmp(ns1->href, ns->href) == 0))))
|
||||
{
|
||||
//xmlFreeNs(ns1);
|
||||
xmlSetNs(node, ns);
|
||||
}
|
||||
|
||||
cleanup_namespaces(node->children, ns);
|
||||
cleanup_namespaces(node->next, ns);
|
||||
if (node->type == XML_ELEMENT_NODE)
|
||||
{
|
||||
cleanup_namespaces((xmlNodePtr)node->properties, ns);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@implementation NSXMLElement
|
||||
|
||||
- (void) dealloc
|
||||
|
@ -91,7 +129,11 @@ GS_PRIVATE_INTERNAL(NSXMLElement)
|
|||
if ((self = [self initWithKind: NSXMLElementKind]) != nil)
|
||||
{
|
||||
[self setName: name];
|
||||
[self setURI: URI];
|
||||
// Without this check this could unset a namespace set via the name
|
||||
if (URI != nil)
|
||||
{
|
||||
[self setURI: URI];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
@ -142,7 +184,7 @@ GS_PRIVATE_INTERNAL(NSXMLElement)
|
|||
{
|
||||
NSString *prefix = [[self class] prefixForName: name];
|
||||
|
||||
if (nil != prefix)
|
||||
if ((nil != prefix) && [prefix length] > 0)
|
||||
{
|
||||
NSXMLNode *ns = [self namespaceForPrefix: prefix];
|
||||
|
||||
|
@ -158,13 +200,14 @@ GS_PRIVATE_INTERNAL(NSXMLElement)
|
|||
{
|
||||
NSMutableArray *results = [NSMutableArray arrayWithCapacity: 10];
|
||||
xmlNodePtr cur = NULL;
|
||||
const xmlChar *xmlName = XMLSTRING(name);
|
||||
|
||||
for (cur = internal->node->children; cur != NULL; cur = cur->next)
|
||||
{
|
||||
if (cur->type == XML_ELEMENT_NODE)
|
||||
{
|
||||
NSString *n = StringFromXMLStringPtr(cur->name);
|
||||
if ([n isEqualToString: name])
|
||||
// FIXME: no namespace or default namespace
|
||||
if ((xmlStrcmp(xmlName, cur->name) == 0) && (cur->ns == NULL))
|
||||
{
|
||||
NSXMLNode *node = [NSXMLNode _objectForNode: cur];
|
||||
[results addObject: node];
|
||||
|
@ -181,6 +224,7 @@ GS_PRIVATE_INTERNAL(NSXMLElement)
|
|||
NSMutableArray *results = [NSMutableArray arrayWithCapacity: 10];
|
||||
xmlNodePtr cur = NULL;
|
||||
const xmlChar *href = XMLSTRING(URI);
|
||||
const xmlChar *xmlName = XMLSTRING(localName);
|
||||
xmlNsPtr parentNS = xmlSearchNsByHref(internal->node->doc, internal->node, href);
|
||||
|
||||
for (cur = internal->node->children; cur != NULL; cur = cur->next)
|
||||
|
@ -194,11 +238,10 @@ GS_PRIVATE_INTERNAL(NSXMLElement)
|
|||
childNS = xmlSearchNsByHref(internal->node->doc, cur, href);
|
||||
}
|
||||
|
||||
if (cur->ns == childNS)
|
||||
if ((cur->ns == childNS) ||
|
||||
((cur->ns == NULL) && (xmlStrcmp(childNS->prefix, "") == 0)))
|
||||
{
|
||||
NSString *n = StringFromXMLStringPtr(cur->name);
|
||||
|
||||
if ([n isEqualToString: localName])
|
||||
if (xmlStrcmp(xmlName, cur->name) == 0)
|
||||
{
|
||||
NSXMLNode *node = [NSXMLNode _objectForNode: cur];
|
||||
[results addObject: node];
|
||||
|
@ -233,6 +276,17 @@ GS_PRIVATE_INTERNAL(NSXMLElement)
|
|||
if (newNs != NULL)
|
||||
{
|
||||
ns = newNs;
|
||||
attr->ns = ns;
|
||||
}
|
||||
}
|
||||
else //if (ns->prefix == NULL)
|
||||
{
|
||||
xmlNsPtr newNs = xmlSearchNsByHref(node->doc, node, ns->href);
|
||||
|
||||
if (newNs != NULL)
|
||||
{
|
||||
ns = newNs;
|
||||
attr->ns = ns;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -331,7 +385,7 @@ GS_PRIVATE_INTERNAL(NSXMLElement)
|
|||
{
|
||||
NSString *prefix = [[self class] prefixForName: name];
|
||||
|
||||
if (nil != prefix)
|
||||
if ((nil != prefix) && [prefix length] > 0)
|
||||
{
|
||||
NSXMLNode *ns = [self namespaceForPrefix: prefix];
|
||||
|
||||
|
@ -376,13 +430,12 @@ GS_PRIVATE_INTERNAL(NSXMLElement)
|
|||
|
||||
- (void) addNamespace: (NSXMLNode*)aNamespace
|
||||
{
|
||||
xmlNsPtr ns = (xmlNsPtr)[aNamespace _node];
|
||||
xmlNsPtr ns = xmlCopyNamespace((xmlNsPtr)[aNamespace _node]);
|
||||
xmlNodePtr node = internal->node;
|
||||
|
||||
if (node->nsDef == NULL)
|
||||
{
|
||||
node->nsDef = ns;
|
||||
[self _addSubNode: aNamespace];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -390,12 +443,17 @@ GS_PRIVATE_INTERNAL(NSXMLElement)
|
|||
xmlNsPtr last = NULL;
|
||||
const xmlChar *prefix = ns->prefix;
|
||||
|
||||
while (xmlStrcmp(prefix, cur->prefix) != 0)
|
||||
while (cur != NULL)
|
||||
{
|
||||
if ((prefix != NULL) &&
|
||||
(cur->prefix != NULL) &&
|
||||
(xmlStrcmp(prefix, cur->prefix) == 0))
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (cur->next == NULL)
|
||||
{
|
||||
cur->next = ns;
|
||||
[self _addSubNode: aNamespace];
|
||||
return;
|
||||
}
|
||||
last = cur;
|
||||
|
@ -422,7 +480,9 @@ GS_PRIVATE_INTERNAL(NSXMLElement)
|
|||
cur->next = NULL;
|
||||
}
|
||||
}
|
||||
// FIXME: Need to replace fake namespaces in subnodes
|
||||
|
||||
// Need to replace fake namespaces in subnodes
|
||||
cleanup_namespaces(node, ns);
|
||||
}
|
||||
|
||||
- (void) removeNamespaceForPrefix: (NSString*)name
|
||||
|
@ -437,7 +497,8 @@ GS_PRIVATE_INTERNAL(NSXMLElement)
|
|||
|
||||
while (cur != NULL)
|
||||
{
|
||||
if (xmlStrcmp(prefix, cur->prefix) == 0)
|
||||
if ((cur->prefix != NULL) &&
|
||||
(xmlStrcmp(prefix, cur->prefix) == 0))
|
||||
{
|
||||
if (last == NULL)
|
||||
{
|
||||
|
@ -452,14 +513,7 @@ GS_PRIVATE_INTERNAL(NSXMLElement)
|
|||
{
|
||||
node->ns = NULL;
|
||||
}
|
||||
if (cur->_private != NULL)
|
||||
{
|
||||
[self _removeSubNode: (NSXMLNode *)cur->_private];
|
||||
}
|
||||
else
|
||||
{
|
||||
xmlFreeNs(cur);
|
||||
}
|
||||
xmlFreeNs(cur);
|
||||
return;
|
||||
}
|
||||
last = cur;
|
||||
|
@ -495,7 +549,8 @@ GS_PRIVATE_INTERNAL(NSXMLElement)
|
|||
result = [NSMutableArray array];
|
||||
for (cur = ns; cur != NULL; cur = cur->next)
|
||||
{
|
||||
[result addObject: [NSXMLNode _objectForNode: (xmlNodePtr)cur]];
|
||||
[result addObject: [NSXMLNode _objectForNode:
|
||||
(xmlNodePtr)xmlCopyNamespace(cur)]];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -510,7 +565,7 @@ GS_PRIVATE_INTERNAL(NSXMLElement)
|
|||
|
||||
if (ns)
|
||||
{
|
||||
return [NSXMLNode _objectForNode: (xmlNodePtr)ns];
|
||||
return [NSXMLNode _objectForNode: (xmlNodePtr)xmlCopyNamespace(ns)];
|
||||
}
|
||||
|
||||
return nil;
|
||||
|
@ -520,6 +575,7 @@ GS_PRIVATE_INTERNAL(NSXMLElement)
|
|||
{
|
||||
NSString *prefix = [[self class] prefixForName: name];
|
||||
|
||||
// Return the default namespace for an empty prefix
|
||||
if (nil != prefix)
|
||||
{
|
||||
return [self namespaceForPrefix: prefix];
|
||||
|
|
|
@ -33,6 +33,34 @@
|
|||
#import "GSInternal.h"
|
||||
GS_PRIVATE_INTERNAL(NSXMLNode)
|
||||
|
||||
extern void
|
||||
cleanup_namespaces(xmlNodePtr node, xmlNsPtr ns);
|
||||
|
||||
static void
|
||||
ensure_oldNs(xmlNodePtr node)
|
||||
{
|
||||
if (node->doc == NULL)
|
||||
{
|
||||
// Create a private document for this node
|
||||
xmlDocPtr tmp = xmlNewDoc((xmlChar *)"1.0");
|
||||
|
||||
#if LIBXML_VERSION >= 20620
|
||||
xmlDOMWrapAdoptNode(NULL, NULL, node, tmp, NULL, 0);
|
||||
#else
|
||||
xmlSetTreeDoc(node, tmp);
|
||||
#endif
|
||||
}
|
||||
if (node->doc->oldNs == NULL)
|
||||
{
|
||||
xmlNsPtr ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
|
||||
memset(ns, 0, sizeof(xmlNs));
|
||||
ns->type = XML_LOCAL_NAMESPACE;
|
||||
ns->href = xmlStrdup(XML_XML_NAMESPACE);
|
||||
ns->prefix = xmlStrdup((const xmlChar *)"xml");
|
||||
node->doc->oldNs = ns;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
countAttributes(xmlNodePtr node)
|
||||
{
|
||||
|
@ -106,7 +134,6 @@ findAttrWithName(xmlNodePtr node, const xmlChar* targetName)
|
|||
return attr;
|
||||
}
|
||||
|
||||
|
||||
static BOOL
|
||||
isEqualAttributes(xmlNodePtr nodeA, xmlNodePtr nodeB)
|
||||
{
|
||||
|
@ -458,16 +485,86 @@ isEqualTree(xmlNodePtr nodeA, xmlNodePtr nodeB)
|
|||
}
|
||||
else
|
||||
{
|
||||
#if LIBXML_VERSION >= 20620
|
||||
xmlDocPtr tmp = childNode->doc;
|
||||
|
||||
if (tmp)
|
||||
{
|
||||
// Try to resolve half defined namespaces
|
||||
xmlNsPtr ns = tmp->oldNs;
|
||||
xmlNsPtr last = NULL;
|
||||
|
||||
ensure_oldNs(parentNode);
|
||||
|
||||
while (ns != NULL)
|
||||
{
|
||||
BOOL resolved = NO;
|
||||
|
||||
if (ns->href == NULL)
|
||||
{
|
||||
xmlNsPtr ns1 = xmlSearchNs(parentNode->doc, parentNode, ns->prefix);
|
||||
|
||||
if (ns1 != NULL)
|
||||
{
|
||||
cleanup_namespaces(childNode, ns1);
|
||||
resolved = YES;
|
||||
}
|
||||
}
|
||||
else if (ns->prefix == NULL)
|
||||
{
|
||||
xmlNsPtr ns1 = xmlSearchNsByHref(parentNode->doc, parentNode, ns->href);
|
||||
|
||||
if (ns1 != NULL)
|
||||
{
|
||||
cleanup_namespaces(childNode, ns1);
|
||||
resolved = YES;
|
||||
}
|
||||
}
|
||||
if (!resolved)
|
||||
{
|
||||
xmlNsPtr cur = ns;
|
||||
xmlNsPtr oldNs1;
|
||||
|
||||
// FIXME: Need to transfer the namespace to the new tree
|
||||
// Unlink in old
|
||||
if (last == NULL)
|
||||
{
|
||||
tmp->oldNs = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
last->next = ns->next;
|
||||
}
|
||||
|
||||
ns = ns->next;
|
||||
cur->next = NULL;
|
||||
|
||||
// Insert in new
|
||||
oldNs1 = parentNode->doc->oldNs;
|
||||
while (oldNs1)
|
||||
{
|
||||
if (oldNs1->next == NULL)
|
||||
{
|
||||
oldNs1->next = cur;
|
||||
break;
|
||||
}
|
||||
oldNs1 = oldNs1->next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
last = ns;
|
||||
ns = ns->next;
|
||||
}
|
||||
}
|
||||
|
||||
#if LIBXML_VERSION >= 20620
|
||||
xmlDOMWrapAdoptNode(NULL, childNode->doc, childNode,
|
||||
parentNode->doc, parentNode, 0);
|
||||
#else
|
||||
xmlSetTreeDoc(childNode, parentNode->doc);
|
||||
#endif
|
||||
xmlFreeDoc(tmp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (mergeTextNodes ||
|
||||
|
@ -1062,7 +1159,6 @@ execute_xpath(NSXMLNode *xmlNode, NSString *xpath_exp, NSString *nmspaces)
|
|||
}
|
||||
[subNodes release];
|
||||
|
||||
[internal->URI release];
|
||||
[internal->objectValue release];
|
||||
[internal->subNodes release];
|
||||
if (node)
|
||||
|
@ -1073,7 +1169,7 @@ execute_xpath(NSXMLNode *xmlNode, NSString *xpath_exp, NSString *nmspaces)
|
|||
// FIXME: Not sure when to free the node here,
|
||||
// the same namespace node might be referenced
|
||||
// from other places.
|
||||
//xmlFreeNode(node);
|
||||
xmlFreeNode(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1123,7 +1219,6 @@ execute_xpath(NSXMLNode *xmlNode, NSString *xpath_exp, NSString *nmspaces)
|
|||
}
|
||||
else
|
||||
{
|
||||
#if LIBXML_VERSION >= 20620
|
||||
if (node->doc)
|
||||
{
|
||||
/* Create a private document and move the node over.
|
||||
|
@ -1134,10 +1229,13 @@ execute_xpath(NSXMLNode *xmlNode, NSString *xpath_exp, NSString *nmspaces)
|
|||
// the method rootDocument
|
||||
xmlDocPtr tmp = xmlNewDoc((xmlChar *)"1.0");
|
||||
|
||||
#if LIBXML_VERSION >= 20620
|
||||
xmlDOMWrapAdoptNode(NULL, node->doc, node, tmp, NULL, 0);
|
||||
#else
|
||||
xmlSetTreeDoc(node, tmp);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// separate our node from its parent and siblings
|
||||
xmlUnlinkNode(node);
|
||||
|
@ -1588,57 +1686,57 @@ execute_xpath(NSXMLNode *xmlNode, NSString *xpath_exp, NSString *nmspaces)
|
|||
}
|
||||
|
||||
localName = xmlSplitQName2(xmlName, &prefix);
|
||||
if (localName != NULL)
|
||||
if (prefix != NULL)
|
||||
{
|
||||
// FIXME: Which other nodes get namespaces?
|
||||
if ((node->type == XML_ATTRIBUTE_NODE) ||
|
||||
(node->type == XML_ELEMENT_NODE))
|
||||
{
|
||||
xmlNsPtr ns;
|
||||
|
||||
// Set namespace
|
||||
if (node->doc == NULL)
|
||||
if ((node->ns != NULL && node->ns->prefix == NULL))
|
||||
{
|
||||
#if LIBXML_VERSION >= 20620
|
||||
// Create a private document for this node
|
||||
xmlDocPtr tmp = xmlNewDoc((xmlChar *)"1.0");
|
||||
|
||||
xmlDOMWrapAdoptNode(NULL, NULL, node, tmp, NULL, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
ns = xmlSearchNs(node->doc, node, prefix);
|
||||
if (ns)
|
||||
{
|
||||
xmlSetNs(node, ns);
|
||||
node->ns->prefix = xmlStrdup(prefix);
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: Fake the name space and fix it later
|
||||
// xmlReconciliateNs or xmlDOMWrapReconcileNamespaces ?
|
||||
// This function is private, so re reimplemt it.
|
||||
//ns = xmlDOMWrapStoreNs(node->doc, NULL, prefix);
|
||||
xmlNsPtr oldNs = node->doc->oldNs;
|
||||
xmlNsPtr ns;
|
||||
|
||||
while (oldNs)
|
||||
// Set namespace
|
||||
ns = xmlSearchNs(node->doc, node, prefix);
|
||||
if (ns)
|
||||
{
|
||||
if (xmlStrEqual(oldNs->prefix, prefix))
|
||||
{
|
||||
ns = oldNs;
|
||||
break;
|
||||
}
|
||||
if (oldNs->next == NULL)
|
||||
{
|
||||
ns = xmlNewNs(NULL, NULL, prefix);
|
||||
oldNs->next = ns;
|
||||
break;
|
||||
}
|
||||
oldNs = oldNs->next;
|
||||
xmlSetNs(node, ns);
|
||||
}
|
||||
else
|
||||
{
|
||||
xmlNsPtr oldNs;
|
||||
|
||||
ensure_oldNs(node);
|
||||
|
||||
// FIXME: Fake the name space and fix it later
|
||||
// xmlReconciliateNs or xmlDOMWrapReconcileNamespaces ?
|
||||
// This function is private, so re reimplemt it.
|
||||
//ns = xmlDOMWrapStoreNs(node->doc, NULL, prefix);
|
||||
oldNs = node->doc->oldNs;
|
||||
while (oldNs)
|
||||
{
|
||||
if (oldNs->prefix != NULL && xmlStrEqual(oldNs->prefix, prefix))
|
||||
{
|
||||
ns = oldNs;
|
||||
break;
|
||||
}
|
||||
if (oldNs->next == NULL)
|
||||
{
|
||||
ns = xmlNewNs(NULL, NULL, prefix);
|
||||
oldNs->next = ns;
|
||||
break;
|
||||
}
|
||||
oldNs = oldNs->next;
|
||||
}
|
||||
xmlSetNs(node, ns);
|
||||
}
|
||||
xmlSetNs(node, ns);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
xmlNodeSetName(node, localName);
|
||||
xmlFree(localName);
|
||||
xmlFree(prefix);
|
||||
|
@ -1688,22 +1786,84 @@ execute_xpath(NSXMLNode *xmlNode, NSString *xpath_exp, NSString *nmspaces)
|
|||
|
||||
- (void) setURI: (NSString*)URI
|
||||
{
|
||||
xmlNodePtr node = internal->node;
|
||||
|
||||
if (NSXMLInvalidKind == internal->kind)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ASSIGNCOPY(internal->URI, URI);
|
||||
//xmlNodeSetBase(internal->node, XMLSTRING(URI));
|
||||
if ((node->type == XML_ATTRIBUTE_NODE) ||
|
||||
(node->type == XML_ELEMENT_NODE))
|
||||
{
|
||||
const xmlChar *uri = XMLSTRING(URI);
|
||||
xmlNsPtr ns;
|
||||
|
||||
if (uri == NULL)
|
||||
{
|
||||
node->ns = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
ns = xmlSearchNsByHref(node->doc, node, uri);
|
||||
if (ns == NULL)
|
||||
{
|
||||
if ((node->ns != NULL && node->ns->href == NULL))
|
||||
{
|
||||
node->ns->href = xmlStrdup(uri);
|
||||
return;
|
||||
}
|
||||
{
|
||||
xmlNsPtr oldNs;
|
||||
|
||||
ensure_oldNs(node);
|
||||
|
||||
// FIXME: Fake the name space and fix it later
|
||||
// xmlReconciliateNs or xmlDOMWrapReconcileNamespaces ?
|
||||
// This function is private, so re reimplemt it.
|
||||
//ns = xmlDOMWrapStoreNs(node->doc, NULL, prefix);
|
||||
oldNs = node->doc->oldNs;
|
||||
while (oldNs)
|
||||
{
|
||||
if (oldNs->href != NULL && xmlStrEqual(oldNs->href, uri))
|
||||
{
|
||||
ns = oldNs;
|
||||
break;
|
||||
}
|
||||
if (oldNs->next == NULL)
|
||||
{
|
||||
ns = xmlNewNs(NULL, uri, NULL);
|
||||
oldNs->next = ns;
|
||||
break;
|
||||
}
|
||||
oldNs = oldNs->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xmlSetNs(node, ns);
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString*) URI
|
||||
{
|
||||
xmlNodePtr node = internal->node;
|
||||
|
||||
if (NSXMLInvalidKind == internal->kind)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
return internal->URI;
|
||||
//return StringFromXMLStringPtr(xmlNodeGetBase(NULL, internal->node));
|
||||
if ((node->type == XML_ATTRIBUTE_NODE) ||
|
||||
(node->type == XML_ELEMENT_NODE))
|
||||
{
|
||||
xmlNsPtr ns = internal->node->ns;
|
||||
|
||||
if ((ns != NULL) && (ns->href != NULL))
|
||||
{
|
||||
return StringFromXMLStringPtr(ns->href);
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString*) XMLString
|
||||
|
|
|
@ -114,7 +114,6 @@ StringFromXMLString(const unsigned char *bytes, unsigned length)
|
|||
GS_XMLNODETYPE *node; \
|
||||
NSUInteger options; \
|
||||
id objectValue; \
|
||||
NSString *URI; \
|
||||
NSMutableArray *subNodes;
|
||||
|
||||
|
||||
|
|
185
Tests/base/NSXMLNode/namespaces.m
Normal file
185
Tests/base/NSXMLNode/namespaces.m
Normal file
|
@ -0,0 +1,185 @@
|
|||
// Based on code with the following copyright:
|
||||
/* Copyright (c) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#import "Testing.h"
|
||||
#import <Foundation/NSAutoreleasePool.h>
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSXMLNode.h>
|
||||
#import <Foundation/NSXMLDocument.h>
|
||||
#import <Foundation/NSXMLElement.h>
|
||||
|
||||
NSString *kGDataNamespaceGData = @"http://schemas.google.com/g/2005";
|
||||
NSString *kGDataNamespaceBatch = @"http://schemas.google.com/gdata/batch";
|
||||
NSString *kGDataNamespaceAtom = @"http://www.w3.org/2005/Atom";
|
||||
NSString *kGDataNamespaceOpenSearch = @"http://a9.com/-/spec/opensearchrss/1.0/";
|
||||
NSString *kGDataNamespaceAtomPrefix = @"atom";
|
||||
|
||||
int main()
|
||||
{
|
||||
START_SET("NSXMLNode namespace handling")
|
||||
NSAutoreleasePool *arp = [NSAutoreleasePool new];
|
||||
|
||||
// create elements and attributes
|
||||
|
||||
// create with URI and local name
|
||||
NSXMLNode *attr1 = [NSXMLNode attributeWithName: @"foo"
|
||||
URI: kGDataNamespaceGData
|
||||
stringValue: @"baz"];
|
||||
NSXMLElement *child1 = [NSXMLNode elementWithName: @"chyld"
|
||||
URI: kGDataNamespaceGData];
|
||||
[child1 setStringValue: @"fuzz"];
|
||||
|
||||
// create with URI and prefix
|
||||
NSXMLNode *attr2 = [NSXMLNode attributeWithName: @"openSearch:foo"
|
||||
stringValue: @"baz2"];
|
||||
NSXMLElement *child2 = [NSXMLNode elementWithName: @"openSearch:chyld"];
|
||||
[child2 setStringValue: @"fuzz2"];
|
||||
|
||||
// create with unqualified local name
|
||||
NSXMLElement *child3 = [NSXMLNode elementWithName: @"chyld"];
|
||||
[child3 setStringValue: @"fuzz3"];
|
||||
|
||||
// create with a missing namespace URI that we'll never actually add,
|
||||
// so we can test searches based on our faked use of {uri}: as
|
||||
// a prefix for the local name
|
||||
NSXMLNode *attr4 = [NSXMLNode attributeWithName: @"zorgbot"
|
||||
URI: kGDataNamespaceBatch
|
||||
stringValue: @"gollyfum"];
|
||||
NSXMLElement *child4 = [NSXMLNode elementWithName: @"zorgtree"
|
||||
URI: kGDataNamespaceBatch];
|
||||
[child4 setStringValue: @"gollyfoo"];
|
||||
|
||||
// create an element with a local namespace not defined in the parent level
|
||||
NSString *lonerURI = @"http://loner.ns";
|
||||
NSXMLElement *child5 = [NSXMLNode elementWithName: @"ln:loner"
|
||||
URI: lonerURI];
|
||||
NSXMLNode *ns5 = [NSXMLNode namespaceWithName: @"ln"
|
||||
stringValue: lonerURI];
|
||||
[child5 addNamespace: ns5];
|
||||
|
||||
// add these to a parent element, along with namespaces
|
||||
NSXMLElement *parent = [NSXMLNode elementWithName: @"dad"];
|
||||
[parent setStringValue: @"buzz"];
|
||||
|
||||
// atom is the default namespace
|
||||
NSXMLNode *nsAtom = [NSXMLNode namespaceWithName: @""
|
||||
stringValue: kGDataNamespaceAtom];
|
||||
[parent addNamespace: nsAtom];
|
||||
|
||||
NSXMLNode *nsGD = [NSXMLNode namespaceWithName: @"gd"
|
||||
stringValue: kGDataNamespaceGData];
|
||||
[parent addNamespace: nsGD];
|
||||
|
||||
NSXMLNode *nsOpenSearch = [NSXMLNode namespaceWithName: @"openSearch"
|
||||
stringValue: kGDataNamespaceOpenSearch];
|
||||
[parent addNamespace: nsOpenSearch];
|
||||
|
||||
[parent addChild: child1];
|
||||
[parent addAttribute: attr1];
|
||||
[parent addChild: child2];
|
||||
[parent addAttribute: attr2];
|
||||
[parent addChild: child3];
|
||||
[parent addChild: child4];
|
||||
[parent addAttribute: attr4];
|
||||
[parent addChild: child5];
|
||||
|
||||
// search for attr1 and child1 by qualified name, since they were
|
||||
// created by URI
|
||||
NSXMLNode *attr1Found = [parent attributeForName: @"gd:foo"];
|
||||
PASS_EQUAL([attr1Found stringValue], @"baz", "attribute gd:foo");
|
||||
|
||||
NSArray *elements = [parent elementsForName: @"gd:chyld"];
|
||||
PASS((int)[elements count] == 1, "getting gd:chyld");
|
||||
if ([elements count] > 0)
|
||||
{
|
||||
NSXMLNode *child1Found = [elements objectAtIndex: 0];
|
||||
PASS_EQUAL([child1Found stringValue], @"fuzz", "child gd:chyld");
|
||||
}
|
||||
|
||||
// search for attr2 and child2 by local name and URI, since they were
|
||||
// created by qualified names
|
||||
NSXMLNode *attr2Found = [parent attributeForLocalName: @"foo"
|
||||
URI: kGDataNamespaceOpenSearch];
|
||||
PASS_EQUAL([attr2Found stringValue], @"baz2", "attribute openSearch:foo");
|
||||
|
||||
NSArray *elements2 = [parent elementsForLocalName: @"chyld"
|
||||
URI: kGDataNamespaceOpenSearch];
|
||||
|
||||
PASS((int)[elements2 count] == 1, "getting openSearch:chyld");
|
||||
if ([elements2 count] > 0)
|
||||
{
|
||||
NSXMLNode *child2Found = [elements2 objectAtIndex: 0];
|
||||
PASS_EQUAL([child2Found stringValue], @"fuzz2", "child openSearch:chyld");
|
||||
}
|
||||
|
||||
// search for child3 by local name
|
||||
NSArray *elements3 = [parent elementsForName: @"chyld"];
|
||||
PASS((int)[elements3 count] == 1, "getting chyld");
|
||||
if ([elements3 count] > 0)
|
||||
{
|
||||
NSXMLNode *child3Found = [elements3 objectAtIndex: 0];
|
||||
PASS_EQUAL([child3Found stringValue], @"fuzz3", "child chyld");
|
||||
}
|
||||
|
||||
// search for child3 by URI
|
||||
NSArray *elements3a = [parent elementsForLocalName: @"chyld"
|
||||
URI: kGDataNamespaceAtom];
|
||||
PASS((int)[elements3a count] == 1, "getting chyld (URI");
|
||||
if ([elements3a count] > 0)
|
||||
{
|
||||
NSXMLNode *child3aFound = [elements3 objectAtIndex: 0];
|
||||
PASS_EQUAL([child3aFound stringValue], @"fuzz3", "child chyld");
|
||||
}
|
||||
|
||||
// search for attr4 and child4 by local name and URI, since they were
|
||||
// created by URI and never bound to a prefix by a namespace declaration
|
||||
NSXMLNode *attr4Found = [parent attributeForLocalName: @"zorgbot"
|
||||
URI: kGDataNamespaceBatch];
|
||||
PASS_EQUAL([attr4Found stringValue], @"gollyfum", "in test batch zorgbot");
|
||||
|
||||
NSArray *elements4 = [parent elementsForLocalName: @"zorgtree"
|
||||
URI: kGDataNamespaceBatch];
|
||||
PASS((int)[elements4 count] == 1, "getting batch zorgtree");
|
||||
if ([elements4 count] > 0)
|
||||
{
|
||||
NSXMLNode *child4Found = [elements4 objectAtIndex: 0];
|
||||
PASS_EQUAL([child4Found stringValue], @"gollyfoo", "in test batch zorgtree");
|
||||
}
|
||||
|
||||
// search for child 5 by local name and URI, since it has a locally-defined
|
||||
// namespace
|
||||
NSArray *elements5 = [parent elementsForLocalName: @"loner"
|
||||
URI: lonerURI];
|
||||
PASS((int)[elements5 count] == 1, "getting loner");
|
||||
|
||||
// test output
|
||||
NSString *expectedXML = @"<dad xmlns=\"http://www.w3.org/2005/Atom\" "
|
||||
"xmlns:gd=\"http://schemas.google.com/g/2005\" "
|
||||
"xmlns:openSearch=\"http://a9.com/-/spec/opensearchrss/1.0/\" "
|
||||
"foo=\"baz\" openSearch:foo=\"baz2\" zorgbot=\"gollyfum\">"
|
||||
"buzz<chyld>fuzz</chyld><openSearch:chyld>fuzz2</openSearch:chyld>"
|
||||
"<chyld>fuzz3</chyld><zorgtree>gollyfoo</zorgtree>"
|
||||
"<ln:loner xmlns:ln=\"http://loner.ns\"></ln:loner></dad>";
|
||||
|
||||
NSString *actualXML = [parent XMLString];
|
||||
testHopeful = YES;
|
||||
PASS_EQUAL(actualXML, expectedXML, "unexpected xml output");
|
||||
testHopeful = NO;
|
||||
|
||||
[arp release];
|
||||
arp = nil;
|
||||
END_SET("NSXMLNode namespace handling")
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue