* 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:
fredkiefer 2012-03-22 09:34:54 +00:00
parent 818d2ee2ae
commit 2079071716
6 changed files with 517 additions and 79 deletions

View file

@ -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.

View file

@ -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";
}

View file

@ -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];

View file

@ -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

View file

@ -114,7 +114,6 @@ StringFromXMLString(const unsigned char *bytes, unsigned length)
GS_XMLNODETYPE *node; \
NSUInteger options; \
id objectValue; \
NSString *URI; \
NSMutableArray *subNodes;

View 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;
}