2009-02-09 16:16:11 +00:00
|
|
|
/* Implementation for NSXMLElement for GNUStep
|
|
|
|
Copyright (C) 2008 Free Software Foundation, Inc.
|
|
|
|
|
|
|
|
Written by: Richard Frith-Macdonald <rfm@gnu.org>
|
|
|
|
Created: September 2008
|
|
|
|
|
|
|
|
This file is part of the GNUstep Base Library.
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 3 of the License, or (at your option) any later version.
|
2012-02-20 03:40:15 +00:00
|
|
|
|
2009-02-09 16:16:11 +00:00
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
|
|
License along with this library; if not, write to the Free
|
|
|
|
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02111 USA.
|
|
|
|
*/
|
|
|
|
|
2010-02-19 08:12:46 +00:00
|
|
|
#import "common.h"
|
|
|
|
|
2012-03-21 08:00:33 +00:00
|
|
|
#if defined(HAVE_LIBXML)
|
|
|
|
|
2012-03-12 13:27:32 +00:00
|
|
|
#define GSInternal NSXMLElementInternal
|
|
|
|
|
2012-01-05 20:40:12 +00:00
|
|
|
#import "NSXMLPrivate.h"
|
|
|
|
#import "GSInternal.h"
|
2012-01-04 12:41:45 +00:00
|
|
|
GS_PRIVATE_INTERNAL(NSXMLElement)
|
|
|
|
|
2012-03-22 17:33:09 +00:00
|
|
|
extern void cleanup_namespaces(xmlNodePtr node, xmlNsPtr ns);
|
|
|
|
extern void ensure_oldNs(xmlNodePtr node);
|
2012-03-22 09:34:54 +00:00
|
|
|
|
2009-02-09 16:16:11 +00:00
|
|
|
@implementation NSXMLElement
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
{
|
2012-03-27 13:24:04 +00:00
|
|
|
if (GS_EXISTS_INTERNAL && internal != nil)
|
2012-01-04 12:41:45 +00:00
|
|
|
{
|
2012-03-21 09:01:48 +00:00
|
|
|
/*
|
|
|
|
NSArray *subNodes = [internal->subNodes copy];
|
|
|
|
NSEnumerator *enumerator = [subNodes objectEnumerator];
|
|
|
|
NSXMLNode *subNode;
|
|
|
|
|
|
|
|
while ((subNode = [enumerator nextObject]) != nil)
|
|
|
|
{
|
|
|
|
if ([subNode kind] == NSXMLNamespaceKind)
|
|
|
|
{
|
|
|
|
[self removeNamespaceForPrefix: [subNode name]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
2012-01-04 12:41:45 +00:00
|
|
|
}
|
2012-03-21 09:01:48 +00:00
|
|
|
|
2009-02-09 16:16:11 +00:00
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
2012-02-20 03:40:15 +00:00
|
|
|
- (void) _createInternal
|
2012-01-05 18:55:17 +00:00
|
|
|
{
|
2012-02-20 03:40:15 +00:00
|
|
|
GS_CREATE_INTERNAL(NSXMLElement);
|
2012-01-05 18:55:17 +00:00
|
|
|
}
|
|
|
|
|
2012-02-20 03:40:15 +00:00
|
|
|
- (id) init
|
2009-02-09 16:16:11 +00:00
|
|
|
{
|
2012-02-20 03:40:15 +00:00
|
|
|
return [self initWithKind: NSXMLElementKind options: 0];
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
2012-04-06 22:27:55 +00:00
|
|
|
- (id) initWithKind: (NSXMLNodeKind)theKind options: (NSUInteger)theOptions
|
2012-01-05 18:55:17 +00:00
|
|
|
{
|
2012-04-06 22:27:55 +00:00
|
|
|
if (NSXMLElementKind == theKind)
|
2012-01-05 18:55:17 +00:00
|
|
|
{
|
2012-04-06 22:27:55 +00:00
|
|
|
return [super initWithKind: theKind options: theOptions];
|
2012-02-20 03:40:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[self release];
|
2012-04-06 22:27:55 +00:00
|
|
|
// This cast is here to keep clang quite that expects an init* method to
|
|
|
|
// return an object of the same class, which is not true here.
|
|
|
|
return (NSXMLElement*)[[NSXMLNode alloc] initWithKind: theKind
|
|
|
|
options: theOptions];
|
2012-01-05 18:55:17 +00:00
|
|
|
}
|
2012-02-20 03:40:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (id) initWithName: (NSString*)name
|
|
|
|
{
|
|
|
|
return [self initWithName: name URI: nil];
|
2012-01-05 18:55:17 +00:00
|
|
|
}
|
|
|
|
|
2009-02-09 16:16:11 +00:00
|
|
|
- (id) initWithName: (NSString*)name URI: (NSString*)URI
|
|
|
|
{
|
2012-03-04 21:40:39 +00:00
|
|
|
if ((self = [self initWithKind: NSXMLElementKind]) != nil)
|
2011-12-30 21:40:12 +00:00
|
|
|
{
|
2012-03-04 21:40:39 +00:00
|
|
|
[self setName: name];
|
2012-03-22 09:34:54 +00:00
|
|
|
// Without this check this could unset a namespace set via the name
|
|
|
|
if (URI != nil)
|
|
|
|
{
|
|
|
|
[self setURI: URI];
|
|
|
|
}
|
2011-12-30 21:40:12 +00:00
|
|
|
}
|
|
|
|
return self;
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (id) initWithName: (NSString*)name stringValue: (NSString*)string
|
|
|
|
{
|
2012-03-04 21:40:39 +00:00
|
|
|
if ((self = [self initWithName: name URI: nil]) != nil)
|
2012-01-03 03:28:25 +00:00
|
|
|
{
|
2012-02-22 10:55:12 +00:00
|
|
|
NSXMLNode *t;
|
2012-03-04 21:40:39 +00:00
|
|
|
|
2012-02-22 10:55:12 +00:00
|
|
|
t = [[NSXMLNode alloc] initWithKind: NSXMLTextKind];
|
|
|
|
[t setStringValue: string];
|
|
|
|
[self addChild: t];
|
|
|
|
[t release];
|
2012-01-03 03:28:25 +00:00
|
|
|
}
|
2012-03-04 21:40:39 +00:00
|
|
|
return self;
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
2012-02-20 03:40:15 +00:00
|
|
|
- (id) initWithXMLString: (NSString*)string
|
|
|
|
error: (NSError**)error
|
2009-02-09 16:16:11 +00:00
|
|
|
{
|
2012-02-20 03:40:15 +00:00
|
|
|
NSXMLElement *result = nil;
|
2012-02-22 22:52:31 +00:00
|
|
|
NSXMLDocument *tempDoc =
|
|
|
|
[[NSXMLDocument alloc] initWithXMLString: string
|
|
|
|
options: 0
|
|
|
|
error: error];
|
|
|
|
if (tempDoc != nil)
|
2012-02-20 03:40:15 +00:00
|
|
|
{
|
2012-02-22 22:52:31 +00:00
|
|
|
result = RETAIN([tempDoc rootElement]);
|
|
|
|
[result detach]; // detach from document.
|
2012-02-20 03:40:15 +00:00
|
|
|
}
|
2012-02-22 22:52:31 +00:00
|
|
|
[tempDoc release];
|
2012-03-04 21:40:39 +00:00
|
|
|
[self release];
|
2012-02-22 22:52:31 +00:00
|
|
|
|
2012-02-20 03:40:15 +00:00
|
|
|
return result;
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
2012-03-05 22:48:18 +00:00
|
|
|
- (id) objectValue
|
|
|
|
{
|
|
|
|
if (internal->objectValue == nil)
|
|
|
|
{
|
|
|
|
return @"";
|
|
|
|
}
|
|
|
|
return internal->objectValue;
|
|
|
|
}
|
|
|
|
|
2009-02-09 16:16:11 +00:00
|
|
|
- (NSArray*) elementsForName: (NSString*)name
|
|
|
|
{
|
2012-03-21 09:01:48 +00:00
|
|
|
NSString *prefix = [[self class] prefixForName: name];
|
2012-02-20 03:40:15 +00:00
|
|
|
|
2012-03-22 09:34:54 +00:00
|
|
|
if ((nil != prefix) && [prefix length] > 0)
|
2012-02-20 03:40:15 +00:00
|
|
|
{
|
2012-03-21 09:01:48 +00:00
|
|
|
NSXMLNode *ns = [self namespaceForPrefix: prefix];
|
|
|
|
|
|
|
|
if (nil != ns)
|
|
|
|
{
|
|
|
|
NSString *localName = [[self class] localNameForName: name];
|
|
|
|
|
|
|
|
// Namespace nodes have the URI as their stringValue
|
|
|
|
return [self elementsForLocalName: localName URI: [ns stringValue]];
|
|
|
|
}
|
2012-02-20 03:40:15 +00:00
|
|
|
}
|
2012-03-21 09:01:48 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
NSMutableArray *results = [NSMutableArray arrayWithCapacity: 10];
|
|
|
|
xmlNodePtr cur = NULL;
|
2012-03-22 09:34:54 +00:00
|
|
|
const xmlChar *xmlName = XMLSTRING(name);
|
2012-03-21 09:01:48 +00:00
|
|
|
|
2018-03-20 17:44:16 +00:00
|
|
|
for (cur = internal->node.node->children; cur != NULL; cur = cur->next)
|
2012-03-21 09:01:48 +00:00
|
|
|
{
|
|
|
|
if (cur->type == XML_ELEMENT_NODE)
|
|
|
|
{
|
2012-03-26 23:11:52 +00:00
|
|
|
// no namespace or default namespace
|
|
|
|
if ((xmlStrcmp(xmlName, cur->name) == 0) &&
|
|
|
|
((cur->ns == NULL) || (cur->ns->prefix == NULL) ||
|
|
|
|
(xmlStrcmp(cur->ns->prefix, (const xmlChar*)"") == 0)))
|
2012-03-21 09:01:48 +00:00
|
|
|
{
|
2012-04-06 22:27:55 +00:00
|
|
|
NSXMLNode *theNode = [NSXMLNode _objectForNode: cur];
|
|
|
|
[results addObject: theNode];
|
2012-03-21 09:01:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-02-20 03:40:15 +00:00
|
|
|
|
2012-03-21 09:01:48 +00:00
|
|
|
return results;
|
|
|
|
}
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray*) elementsForLocalName: (NSString*)localName URI: (NSString*)URI
|
|
|
|
{
|
2012-03-21 09:01:48 +00:00
|
|
|
NSMutableArray *results = [NSMutableArray arrayWithCapacity: 10];
|
|
|
|
xmlNodePtr cur = NULL;
|
|
|
|
const xmlChar *href = XMLSTRING(URI);
|
2012-03-22 09:34:54 +00:00
|
|
|
const xmlChar *xmlName = XMLSTRING(localName);
|
2018-03-20 17:44:16 +00:00
|
|
|
xmlNsPtr parentNS = xmlSearchNsByHref(internal->node.node->doc, internal->node.node, href);
|
2012-03-21 09:01:48 +00:00
|
|
|
|
2018-03-20 17:44:16 +00:00
|
|
|
for (cur = internal->node.node->children; cur != NULL; cur = cur->next)
|
2012-03-21 09:01:48 +00:00
|
|
|
{
|
|
|
|
if (cur->type == XML_ELEMENT_NODE)
|
|
|
|
{
|
2012-03-26 23:11:52 +00:00
|
|
|
if (xmlStrcmp(xmlName, cur->name) == 0)
|
2012-03-21 09:01:48 +00:00
|
|
|
{
|
2012-03-26 23:11:52 +00:00
|
|
|
xmlNsPtr childNS = parentNS;
|
2012-03-21 09:01:48 +00:00
|
|
|
|
2012-03-26 23:11:52 +00:00
|
|
|
if (cur->nsDef != NULL)
|
|
|
|
{
|
2018-03-20 17:44:16 +00:00
|
|
|
childNS = xmlSearchNsByHref(internal->node.node->doc, cur, href);
|
2012-03-26 23:11:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (((childNS != NULL) &&
|
|
|
|
((cur->ns == childNS) ||
|
|
|
|
((cur->ns == NULL) &&
|
|
|
|
(xmlStrcmp(childNS->prefix, (const xmlChar*)"") == 0)))) ||
|
|
|
|
((cur->ns != NULL) && (xmlStrcmp(cur->ns->href, href) == 0)))
|
2012-03-21 09:01:48 +00:00
|
|
|
{
|
2012-04-06 22:27:55 +00:00
|
|
|
NSXMLNode *theNode = [NSXMLNode _objectForNode: cur];
|
|
|
|
[results addObject: theNode];
|
2012-03-21 09:01:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return results;
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) addAttribute: (NSXMLNode*)attribute
|
|
|
|
{
|
2018-03-20 17:44:16 +00:00
|
|
|
xmlNodePtr theNode = internal->node.node;
|
2012-02-20 03:40:15 +00:00
|
|
|
xmlAttrPtr attr = (xmlAttrPtr)[attribute _node];
|
2012-03-21 09:01:48 +00:00
|
|
|
xmlAttrPtr oldAttr;
|
2012-03-04 21:40:39 +00:00
|
|
|
|
2012-02-20 03:40:15 +00:00
|
|
|
if (nil != [attribute parent])
|
2012-03-01 06:11:30 +00:00
|
|
|
{
|
2012-03-05 09:41:40 +00:00
|
|
|
[NSException raise: NSInternalInconsistencyException
|
2012-03-01 06:11:30 +00:00
|
|
|
format: @"Tried to add attribute to multiple parents."];
|
|
|
|
}
|
2012-02-20 03:40:15 +00:00
|
|
|
|
2012-03-21 09:01:48 +00:00
|
|
|
if (attr->ns != NULL)
|
|
|
|
{
|
|
|
|
xmlNsPtr ns = attr->ns;
|
2012-03-22 17:33:09 +00:00
|
|
|
xmlDocPtr tmp = attr->doc;
|
|
|
|
BOOL resolved = NO;
|
2012-03-21 09:01:48 +00:00
|
|
|
|
|
|
|
if (ns->href == NULL)
|
|
|
|
{
|
2012-04-06 22:27:55 +00:00
|
|
|
xmlNsPtr newNs = xmlSearchNs(theNode->doc, theNode, ns->prefix);
|
2012-03-21 09:01:48 +00:00
|
|
|
|
|
|
|
if (newNs != NULL)
|
|
|
|
{
|
|
|
|
ns = newNs;
|
2012-03-22 09:34:54 +00:00
|
|
|
attr->ns = ns;
|
2012-03-22 17:33:09 +00:00
|
|
|
resolved = YES;
|
2012-03-22 09:34:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else //if (ns->prefix == NULL)
|
|
|
|
{
|
2012-04-06 22:27:55 +00:00
|
|
|
xmlNsPtr newNs = xmlSearchNsByHref(theNode->doc, theNode, ns->href);
|
2012-03-22 09:34:54 +00:00
|
|
|
|
|
|
|
if (newNs != NULL)
|
|
|
|
{
|
|
|
|
ns = newNs;
|
|
|
|
attr->ns = ns;
|
2012-03-22 17:33:09 +00:00
|
|
|
resolved = YES;
|
2012-03-21 09:01:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-22 17:33:09 +00:00
|
|
|
if (!resolved && (tmp != NULL))
|
|
|
|
{
|
|
|
|
xmlNsPtr cur = tmp->oldNs;
|
|
|
|
xmlNsPtr last = NULL;
|
|
|
|
xmlNsPtr oldNs1;
|
|
|
|
|
|
|
|
// Need to transfer the namespace to the new tree
|
|
|
|
// Unlink in old
|
|
|
|
while (cur)
|
|
|
|
{
|
|
|
|
if (cur == ns)
|
|
|
|
{
|
|
|
|
if (last == NULL)
|
|
|
|
{
|
|
|
|
tmp->oldNs = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-02-08 23:07:53 +00:00
|
|
|
last->next = cur->next;
|
2012-03-22 17:33:09 +00:00
|
|
|
}
|
|
|
|
cur->next = NULL;
|
|
|
|
break;
|
2018-02-08 23:07:53 +00:00
|
|
|
}
|
|
|
|
last = cur;
|
2012-03-22 17:33:09 +00:00
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Insert in new
|
2012-04-06 22:27:55 +00:00
|
|
|
ensure_oldNs(theNode);
|
|
|
|
oldNs1 = theNode->doc->oldNs;
|
2012-03-22 17:33:09 +00:00
|
|
|
while (oldNs1)
|
|
|
|
{
|
|
|
|
if (oldNs1->next == NULL)
|
|
|
|
{
|
|
|
|
oldNs1->next = cur;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
oldNs1 = oldNs1->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if LIBXML_VERSION >= 20620
|
|
|
|
xmlDOMWrapAdoptNode(NULL, attr->doc, (xmlNodePtr)attr,
|
2012-04-06 22:27:55 +00:00
|
|
|
theNode->doc, theNode, 0);
|
2012-03-22 17:33:09 +00:00
|
|
|
#else
|
2012-04-06 22:27:55 +00:00
|
|
|
xmlSetTreeDoc((xmlNodePtr)attr, theNode->doc);
|
2012-03-22 17:33:09 +00:00
|
|
|
#endif
|
|
|
|
xmlFreeDoc(tmp);
|
|
|
|
|
2012-04-06 22:27:55 +00:00
|
|
|
oldAttr = xmlHasNsProp(theNode, attr->name, ns->href);
|
2012-03-21 09:01:48 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-04-06 22:27:55 +00:00
|
|
|
oldAttr = xmlHasProp(theNode, attr->name);
|
2012-03-21 09:01:48 +00:00
|
|
|
}
|
|
|
|
|
2012-02-20 03:40:15 +00:00
|
|
|
if (NULL != oldAttr)
|
2012-03-01 06:11:30 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* As per Cocoa documentation, we only add the attribute if it's not
|
|
|
|
* already set. xmlHasProp() also looks at the DTD for default attributes
|
|
|
|
* and we need to make sure that we only bail out here on #FIXED
|
|
|
|
* attributes.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Do not replace plain attributes.
|
|
|
|
if (XML_ATTRIBUTE_NODE == oldAttr->type)
|
2012-02-20 03:40:15 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2012-03-01 06:11:30 +00:00
|
|
|
else if (XML_ATTRIBUTE_DECL == oldAttr->type)
|
2012-02-20 03:40:15 +00:00
|
|
|
{
|
2012-03-01 06:11:30 +00:00
|
|
|
// If the attribute is from a DTD, do not replace it if it's #FIXED
|
|
|
|
xmlAttributePtr attrDecl = (xmlAttributePtr)oldAttr;
|
|
|
|
if (XML_ATTRIBUTE_FIXED == attrDecl->def)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2012-02-20 03:40:15 +00:00
|
|
|
}
|
2012-03-01 06:11:30 +00:00
|
|
|
}
|
2012-04-06 22:27:55 +00:00
|
|
|
xmlAddChild(theNode, (xmlNodePtr)attr);
|
2012-03-04 21:40:39 +00:00
|
|
|
[self _addSubNode: attribute];
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) removeAttributeForName: (NSString*)name
|
|
|
|
{
|
2012-03-12 19:50:51 +00:00
|
|
|
NSXMLNode *attrNode = [self attributeForName: name];
|
2012-02-20 03:40:15 +00:00
|
|
|
|
2012-03-04 21:40:39 +00:00
|
|
|
[attrNode detach];
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setAttributes: (NSArray*)attributes
|
|
|
|
{
|
|
|
|
NSEnumerator *enumerator = [attributes objectEnumerator];
|
|
|
|
NSXMLNode *attribute;
|
|
|
|
|
2012-03-04 21:40:39 +00:00
|
|
|
// FIXME: Remove all previous attributes
|
2009-02-09 16:16:11 +00:00
|
|
|
while ((attribute = [enumerator nextObject]) != nil)
|
|
|
|
{
|
|
|
|
[self addAttribute: attribute];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setAttributesAsDictionary: (NSDictionary*)attributes
|
2012-01-06 12:22:30 +00:00
|
|
|
{
|
|
|
|
[self setAttributesWithDictionary: attributes];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setAttributesWithDictionary: (NSDictionary*)attributes
|
2009-02-09 16:16:11 +00:00
|
|
|
{
|
2012-02-20 03:40:15 +00:00
|
|
|
NSEnumerator *en = [attributes keyEnumerator];
|
|
|
|
NSString *key;
|
|
|
|
|
2012-03-04 21:40:39 +00:00
|
|
|
// FIXME: Remove all previous attributes
|
2012-02-20 03:40:15 +00:00
|
|
|
while ((key = [en nextObject]) != nil)
|
|
|
|
{
|
|
|
|
NSString *val = [[attributes objectForKey: key] stringValue];
|
|
|
|
NSXMLNode *attribute = [NSXMLNode attributeWithName: key
|
2012-01-05 15:44:45 +00:00
|
|
|
stringValue: val];
|
2012-02-20 03:40:15 +00:00
|
|
|
[self addAttribute: attribute];
|
2012-01-05 15:44:45 +00:00
|
|
|
}
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray*) attributes
|
|
|
|
{
|
2012-03-04 21:40:39 +00:00
|
|
|
NSMutableArray *attributes = [NSMutableArray array];
|
2018-03-20 17:44:16 +00:00
|
|
|
xmlNodePtr theNode = internal->node.node;
|
2012-04-06 22:27:55 +00:00
|
|
|
xmlAttrPtr attributeNode = theNode->properties;
|
2012-03-01 06:11:30 +00:00
|
|
|
|
2012-02-20 03:40:15 +00:00
|
|
|
while (attributeNode)
|
|
|
|
{
|
2012-03-01 06:11:30 +00:00
|
|
|
NSXMLNode *attribute;
|
2012-03-04 21:40:39 +00:00
|
|
|
|
|
|
|
attribute = [NSXMLNode _objectForNode: (xmlNodePtr)attributeNode];
|
|
|
|
[attributes addObject: attribute];
|
2012-02-20 03:40:15 +00:00
|
|
|
attributeNode = attributeNode->next;
|
|
|
|
}
|
|
|
|
return attributes;
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSXMLNode*) attributeForName: (NSString*)name
|
|
|
|
{
|
2012-03-21 09:01:48 +00:00
|
|
|
NSString *prefix = [[self class] prefixForName: name];
|
2012-03-01 06:11:30 +00:00
|
|
|
|
2012-03-22 09:34:54 +00:00
|
|
|
if ((nil != prefix) && [prefix length] > 0)
|
2012-03-01 06:11:30 +00:00
|
|
|
{
|
2012-03-21 09:01:48 +00:00
|
|
|
NSXMLNode *ns = [self namespaceForPrefix: prefix];
|
|
|
|
|
|
|
|
if (nil != ns)
|
|
|
|
{
|
|
|
|
NSString *localName = [[self class] localNameForName: name];
|
|
|
|
|
|
|
|
// Namespace nodes have the URI as their stringValue
|
|
|
|
return [self attributeForLocalName: localName URI: [ns stringValue]];
|
|
|
|
}
|
2012-03-01 06:11:30 +00:00
|
|
|
}
|
2012-03-04 21:40:39 +00:00
|
|
|
|
2012-03-21 09:01:48 +00:00
|
|
|
{
|
|
|
|
NSXMLNode *result = nil;
|
2018-03-20 17:44:16 +00:00
|
|
|
xmlNodePtr theNode = internal->node.node;
|
2012-04-06 22:27:55 +00:00
|
|
|
xmlAttrPtr attributeNode = xmlHasProp(theNode, XMLSTRING(name));
|
2012-03-21 09:01:48 +00:00
|
|
|
|
|
|
|
if (NULL != attributeNode)
|
|
|
|
{
|
|
|
|
result = [NSXMLNode _objectForNode: (xmlNodePtr)attributeNode];
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSXMLNode*) attributeForLocalName: (NSString*)localName
|
2012-01-06 12:22:30 +00:00
|
|
|
URI: (NSString*)URI
|
2009-02-09 16:16:11 +00:00
|
|
|
{
|
2012-03-21 09:01:48 +00:00
|
|
|
NSXMLNode *result = nil;
|
2018-03-20 17:44:16 +00:00
|
|
|
xmlNodePtr theNode = internal->node.node;
|
2012-04-06 22:27:55 +00:00
|
|
|
xmlAttrPtr attributeNode = xmlHasNsProp(theNode, XMLSTRING(localName),
|
2012-03-21 09:01:48 +00:00
|
|
|
XMLSTRING(URI));
|
|
|
|
|
|
|
|
if (NULL != attributeNode)
|
|
|
|
{
|
|
|
|
result = [NSXMLNode _objectForNode: (xmlNodePtr)attributeNode];
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) addNamespace: (NSXMLNode*)aNamespace
|
|
|
|
{
|
2012-03-22 09:34:54 +00:00
|
|
|
xmlNsPtr ns = xmlCopyNamespace((xmlNsPtr)[aNamespace _node]);
|
2018-03-20 17:44:16 +00:00
|
|
|
xmlNodePtr theNode = internal->node.node;
|
2012-03-26 23:11:52 +00:00
|
|
|
const xmlChar *prefix = ns->prefix;
|
2012-02-23 00:01:27 +00:00
|
|
|
|
2012-04-06 22:27:55 +00:00
|
|
|
if (theNode->nsDef == NULL)
|
2012-02-23 00:01:27 +00:00
|
|
|
{
|
2012-04-06 22:27:55 +00:00
|
|
|
theNode->nsDef = ns;
|
2012-02-23 00:01:27 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-04-06 22:27:55 +00:00
|
|
|
xmlNsPtr cur = theNode->nsDef;
|
2012-03-21 09:01:48 +00:00
|
|
|
xmlNsPtr last = NULL;
|
2012-02-23 00:01:27 +00:00
|
|
|
|
2012-03-22 09:34:54 +00:00
|
|
|
while (cur != NULL)
|
2012-02-23 00:01:27 +00:00
|
|
|
{
|
2012-03-22 09:34:54 +00:00
|
|
|
if ((prefix != NULL) &&
|
|
|
|
(cur->prefix != NULL) &&
|
|
|
|
(xmlStrcmp(prefix, cur->prefix) == 0))
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2012-02-23 00:01:27 +00:00
|
|
|
if (cur->next == NULL)
|
|
|
|
{
|
|
|
|
cur->next = ns;
|
|
|
|
return;
|
|
|
|
}
|
2012-03-21 09:01:48 +00:00
|
|
|
last = cur;
|
2012-02-23 00:01:27 +00:00
|
|
|
cur = cur->next;
|
|
|
|
}
|
2012-03-21 09:01:48 +00:00
|
|
|
|
|
|
|
// Found the same prefix
|
|
|
|
if (cur->href == NULL)
|
|
|
|
{
|
|
|
|
// This was a fake namespace we added
|
2012-04-06 22:27:55 +00:00
|
|
|
if (theNode->ns == cur)
|
2012-03-21 09:01:48 +00:00
|
|
|
{
|
2012-04-06 22:27:55 +00:00
|
|
|
theNode->ns = ns;
|
2012-03-21 09:01:48 +00:00
|
|
|
}
|
|
|
|
if (last == NULL)
|
|
|
|
{
|
2012-04-06 22:27:55 +00:00
|
|
|
theNode->nsDef = ns;
|
2012-03-21 09:01:48 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
last->next = ns;
|
|
|
|
}
|
|
|
|
ns->next = cur->next;
|
|
|
|
cur->next = NULL;
|
|
|
|
}
|
2012-02-23 00:01:27 +00:00
|
|
|
}
|
2012-03-22 09:34:54 +00:00
|
|
|
|
2012-03-26 23:11:52 +00:00
|
|
|
// Are we setting a default namespace?
|
2012-04-06 22:27:55 +00:00
|
|
|
if ((theNode->ns == NULL) && (xmlStrcmp(prefix, (const xmlChar*)"") == 0))
|
2012-03-26 23:11:52 +00:00
|
|
|
{
|
2012-04-06 22:27:55 +00:00
|
|
|
theNode->ns = ns;
|
2012-03-26 23:11:52 +00:00
|
|
|
}
|
|
|
|
|
2012-03-22 09:34:54 +00:00
|
|
|
// Need to replace fake namespaces in subnodes
|
2012-04-06 22:27:55 +00:00
|
|
|
cleanup_namespaces(theNode, ns);
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) removeNamespaceForPrefix: (NSString*)name
|
|
|
|
{
|
2018-03-20 17:44:16 +00:00
|
|
|
xmlNodePtr theNode = internal->node.node;
|
2012-03-21 09:01:48 +00:00
|
|
|
|
2012-04-06 22:27:55 +00:00
|
|
|
if (theNode->nsDef != NULL)
|
2012-03-12 22:33:27 +00:00
|
|
|
{
|
2012-04-06 22:27:55 +00:00
|
|
|
xmlNsPtr cur = theNode->nsDef;
|
2012-03-12 22:33:27 +00:00
|
|
|
xmlNsPtr last = NULL;
|
|
|
|
const xmlChar *prefix = XMLSTRING(name);
|
|
|
|
|
|
|
|
while (cur != NULL)
|
|
|
|
{
|
2012-03-22 09:34:54 +00:00
|
|
|
if ((cur->prefix != NULL) &&
|
|
|
|
(xmlStrcmp(prefix, cur->prefix) == 0))
|
2012-03-12 22:33:27 +00:00
|
|
|
{
|
|
|
|
if (last == NULL)
|
|
|
|
{
|
2018-03-20 17:44:16 +00:00
|
|
|
internal->node.node->nsDef = cur->next;
|
2012-03-12 22:33:27 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
last->next = cur->next;
|
|
|
|
}
|
|
|
|
cur->next = NULL;
|
2012-04-06 22:27:55 +00:00
|
|
|
if (theNode->ns == cur)
|
2012-03-21 09:01:48 +00:00
|
|
|
{
|
2012-04-06 22:27:55 +00:00
|
|
|
theNode->ns = NULL;
|
2012-03-21 09:01:48 +00:00
|
|
|
}
|
2012-03-22 09:34:54 +00:00
|
|
|
xmlFreeNs(cur);
|
2012-03-12 22:33:27 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
last = cur;
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
}
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setNamespaces: (NSArray*)namespaces
|
|
|
|
{
|
2012-02-20 03:40:15 +00:00
|
|
|
NSEnumerator *en = [namespaces objectEnumerator];
|
2012-02-23 00:01:27 +00:00
|
|
|
NSXMLNode *namespace = nil;
|
2009-02-09 16:16:11 +00:00
|
|
|
|
2012-03-26 23:11:52 +00:00
|
|
|
// Remove old namespaces
|
2018-03-20 17:44:16 +00:00
|
|
|
xmlFreeNsList(internal->node.node->nsDef);
|
|
|
|
internal->node.node->nsDef = NULL;
|
2012-03-26 23:11:52 +00:00
|
|
|
|
|
|
|
// Add new ones
|
2012-02-23 00:01:27 +00:00
|
|
|
while ((namespace = (NSXMLNode *)[en nextObject]) != nil)
|
2012-01-06 12:22:30 +00:00
|
|
|
{
|
2012-03-12 22:33:27 +00:00
|
|
|
[self addNamespace: namespace];
|
2012-01-06 12:22:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-09 16:16:11 +00:00
|
|
|
- (NSArray*) namespaces
|
|
|
|
{
|
2012-03-21 09:01:48 +00:00
|
|
|
// FIXME: Should we use xmlGetNsList()?
|
2012-02-20 03:40:15 +00:00
|
|
|
NSMutableArray *result = nil;
|
2018-03-20 17:44:16 +00:00
|
|
|
xmlNsPtr ns = internal->node.node->nsDef;
|
2012-02-20 03:40:15 +00:00
|
|
|
|
2012-02-22 22:52:31 +00:00
|
|
|
if (ns)
|
2012-02-20 03:40:15 +00:00
|
|
|
{
|
|
|
|
xmlNsPtr cur = NULL;
|
2012-03-21 09:01:48 +00:00
|
|
|
|
2012-02-20 03:40:15 +00:00
|
|
|
result = [NSMutableArray array];
|
2012-02-22 22:52:31 +00:00
|
|
|
for (cur = ns; cur != NULL; cur = cur->next)
|
2012-02-20 03:40:15 +00:00
|
|
|
{
|
2012-03-22 09:34:54 +00:00
|
|
|
[result addObject: [NSXMLNode _objectForNode:
|
|
|
|
(xmlNodePtr)xmlCopyNamespace(cur)]];
|
2012-02-20 03:40:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-22 22:52:31 +00:00
|
|
|
return result;
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSXMLNode*) namespaceForPrefix: (NSString*)name
|
|
|
|
{
|
2012-03-26 23:11:52 +00:00
|
|
|
if (name != nil)
|
2012-02-22 22:52:31 +00:00
|
|
|
{
|
2012-03-26 23:11:52 +00:00
|
|
|
const xmlChar *prefix = XMLSTRING(name);
|
2018-03-20 17:44:16 +00:00
|
|
|
xmlNodePtr theNode = internal->node.node;
|
2012-03-26 23:11:52 +00:00
|
|
|
xmlNsPtr ns;
|
|
|
|
|
2012-04-06 22:27:55 +00:00
|
|
|
ns = xmlSearchNs(theNode->doc, theNode, prefix);
|
2012-03-26 23:11:52 +00:00
|
|
|
if ((ns == NULL) && ([name length] == 0))
|
|
|
|
{
|
|
|
|
prefix = NULL;
|
2012-04-06 22:27:55 +00:00
|
|
|
ns = xmlSearchNs(theNode->doc, theNode, prefix);
|
2012-03-26 23:11:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ns != NULL)
|
|
|
|
{
|
|
|
|
return [NSXMLNode _objectForNode: (xmlNodePtr)xmlCopyNamespace(ns)];
|
|
|
|
}
|
2012-02-22 22:52:31 +00:00
|
|
|
}
|
|
|
|
|
2009-02-09 16:16:11 +00:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSXMLNode*) resolveNamespaceForName: (NSString*)name
|
|
|
|
{
|
2012-02-23 00:01:27 +00:00
|
|
|
NSString *prefix = [[self class] prefixForName: name];
|
|
|
|
|
2012-03-22 09:34:54 +00:00
|
|
|
// Return the default namespace for an empty prefix
|
2012-02-23 00:01:27 +00:00
|
|
|
if (nil != prefix)
|
|
|
|
{
|
|
|
|
return [self namespaceForPrefix: prefix];
|
|
|
|
}
|
|
|
|
|
2009-02-09 16:16:11 +00:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString*) resolvePrefixForNamespaceURI: (NSString*)namespaceURI
|
|
|
|
{
|
2012-03-21 09:01:48 +00:00
|
|
|
const xmlChar *uri = XMLSTRING(namespaceURI);
|
2018-03-20 17:44:16 +00:00
|
|
|
xmlNsPtr ns = xmlSearchNsByHref(internal->node.node->doc, internal->node.node, uri);
|
2012-02-23 00:01:27 +00:00
|
|
|
|
|
|
|
if (ns)
|
|
|
|
{
|
2012-03-21 09:01:48 +00:00
|
|
|
return StringFromXMLStringPtr(ns->prefix);
|
2012-02-23 00:01:27 +00:00
|
|
|
}
|
|
|
|
|
2009-02-09 16:16:11 +00:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) insertChild: (NSXMLNode*)child atIndex: (NSUInteger)index
|
|
|
|
{
|
2012-04-06 22:27:55 +00:00
|
|
|
NSXMLNodeKind theKind = [child kind];
|
2012-02-20 03:40:15 +00:00
|
|
|
NSUInteger childCount = [self childCount];
|
2012-01-06 12:22:30 +00:00
|
|
|
|
2012-02-20 03:40:15 +00:00
|
|
|
// Check to make sure this is a valid addition...
|
2012-01-06 12:22:30 +00:00
|
|
|
NSAssert(nil != child, NSInvalidArgumentException);
|
2012-02-20 03:40:15 +00:00
|
|
|
NSAssert(index <= childCount, NSInvalidArgumentException);
|
2012-04-06 22:27:55 +00:00
|
|
|
NSAssert(NSXMLAttributeKind != theKind, NSInvalidArgumentException);
|
|
|
|
NSAssert(NSXMLDTDKind != theKind, NSInvalidArgumentException);
|
|
|
|
NSAssert(NSXMLDocumentKind != theKind, NSInvalidArgumentException);
|
|
|
|
NSAssert(NSXMLElementDeclarationKind != theKind, NSInvalidArgumentException);
|
|
|
|
NSAssert(NSXMLEntityDeclarationKind != theKind, NSInvalidArgumentException);
|
|
|
|
NSAssert(NSXMLInvalidKind != theKind, NSInvalidArgumentException);
|
|
|
|
NSAssert(NSXMLNamespaceKind != theKind, NSInvalidArgumentException);
|
|
|
|
NSAssert(NSXMLNotationDeclarationKind != theKind, NSInvalidArgumentException);
|
2012-01-06 12:22:30 +00:00
|
|
|
|
2015-12-22 18:35:37 +00:00
|
|
|
/* On OSX we get NSInternalInconsistencyException if we try to add an element
|
|
|
|
* which is already a child of some other parent. So presumably we shouldn't
|
|
|
|
* be auto-removing...
|
|
|
|
*
|
|
|
|
* if (nil != [child parent])
|
|
|
|
* {
|
|
|
|
* [child detach];
|
|
|
|
* }
|
|
|
|
*/
|
|
|
|
NSAssert(nil == [child parent], NSInternalInconsistencyException);
|
2015-11-02 18:10:38 +00:00
|
|
|
|
2012-02-22 22:52:31 +00:00
|
|
|
[self _insertChild: child atIndex: index];
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) insertChildren: (NSArray*)children atIndex: (NSUInteger)index
|
|
|
|
{
|
|
|
|
NSEnumerator *enumerator = [children objectEnumerator];
|
|
|
|
NSXMLNode *child;
|
2012-02-20 03:40:15 +00:00
|
|
|
|
2009-02-09 16:16:11 +00:00
|
|
|
while ((child = [enumerator nextObject]) != nil)
|
|
|
|
{
|
|
|
|
[self insertChild: child atIndex: index++];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) removeChildAtIndex: (NSUInteger)index
|
|
|
|
{
|
2012-02-22 22:52:31 +00:00
|
|
|
NSXMLNode *child;
|
2012-01-06 12:22:30 +00:00
|
|
|
|
2012-02-20 03:40:15 +00:00
|
|
|
if (index >= [self childCount])
|
2012-01-06 12:22:30 +00:00
|
|
|
{
|
2012-01-07 13:08:03 +00:00
|
|
|
[NSException raise: NSRangeException
|
2012-03-04 21:40:39 +00:00
|
|
|
format: @"index too large"];
|
2012-01-06 12:22:30 +00:00
|
|
|
}
|
2012-02-20 03:40:15 +00:00
|
|
|
|
2012-02-22 22:52:31 +00:00
|
|
|
child = [self childAtIndex: index];
|
|
|
|
[child detach];
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setChildren: (NSArray*)children
|
|
|
|
{
|
2012-02-22 22:52:31 +00:00
|
|
|
NSUInteger count = [self childCount];
|
2012-01-06 12:22:30 +00:00
|
|
|
|
2012-02-22 22:52:31 +00:00
|
|
|
while (count-- > 0)
|
2012-02-20 03:40:15 +00:00
|
|
|
{
|
2012-02-22 22:52:31 +00:00
|
|
|
[self removeChildAtIndex: count];
|
2012-01-06 02:43:26 +00:00
|
|
|
}
|
2012-02-22 22:52:31 +00:00
|
|
|
|
|
|
|
[self insertChildren: children atIndex: 0];
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
2012-02-20 03:40:15 +00:00
|
|
|
|
2009-02-09 16:16:11 +00:00
|
|
|
- (void) addChild: (NSXMLNode*)child
|
|
|
|
{
|
2012-02-22 22:52:31 +00:00
|
|
|
[self insertChild: child atIndex: [self childCount]];
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
2012-02-20 03:40:15 +00:00
|
|
|
|
2012-04-06 22:27:55 +00:00
|
|
|
- (void) replaceChildAtIndex: (NSUInteger)index withNode: (NSXMLNode*)theNode
|
2009-02-09 16:16:11 +00:00
|
|
|
{
|
2012-04-06 22:27:55 +00:00
|
|
|
[self insertChild: theNode atIndex: index];
|
2012-01-06 12:22:30 +00:00
|
|
|
[self removeChildAtIndex: index + 1];
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
2012-03-01 06:11:30 +00:00
|
|
|
static void
|
|
|
|
joinTextNodes(xmlNodePtr nodeA, xmlNodePtr nodeB, NSMutableArray *nodesToDelete)
|
2012-01-03 17:15:29 +00:00
|
|
|
{
|
2012-03-04 21:40:39 +00:00
|
|
|
NSXMLNode *objA = (nodeA->_private);
|
|
|
|
NSXMLNode *objB = (nodeB->_private);
|
2012-01-03 17:15:29 +00:00
|
|
|
|
2012-02-20 03:40:15 +00:00
|
|
|
xmlTextMerge(nodeA, nodeB); // merge nodeB into nodeA
|
2012-01-03 17:15:29 +00:00
|
|
|
|
2012-02-20 03:40:15 +00:00
|
|
|
if (objA != nil) // objA gets the merged node
|
2012-01-03 17:15:29 +00:00
|
|
|
{
|
2012-02-20 03:40:15 +00:00
|
|
|
if (objB != nil) // objB is now invalid
|
|
|
|
{
|
2012-03-01 06:11:30 +00:00
|
|
|
/* set it to be invalid and make sure it's not
|
|
|
|
* pointing to a freed node
|
|
|
|
*/
|
|
|
|
[objB _invalidate];
|
2012-03-04 21:40:39 +00:00
|
|
|
[nodesToDelete addObject: objB];
|
2012-02-20 03:40:15 +00:00
|
|
|
}
|
2012-01-03 17:15:29 +00:00
|
|
|
}
|
2012-02-20 03:40:15 +00:00
|
|
|
else if (objB != nil) // there is no objA -- objB gets the merged node
|
2012-01-03 17:15:29 +00:00
|
|
|
{
|
2012-03-04 21:40:39 +00:00
|
|
|
[objB _setNode: nodeA]; // nodeA is the remaining (merged) node
|
2012-01-03 17:15:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-20 03:40:15 +00:00
|
|
|
- (void) normalizeAdjacentTextNodesPreservingCDATA: (BOOL)preserve
|
2012-01-06 02:43:26 +00:00
|
|
|
{
|
2012-02-20 03:40:15 +00:00
|
|
|
NSEnumerator *subEnum = [internal->subNodes objectEnumerator];
|
|
|
|
NSXMLNode *subNode = nil;
|
|
|
|
NSMutableArray *nodesToDelete = [NSMutableArray array];
|
2012-03-01 06:11:30 +00:00
|
|
|
|
2012-02-20 03:40:15 +00:00
|
|
|
while ((subNode = [subEnum nextObject]))
|
2012-01-06 02:43:26 +00:00
|
|
|
{
|
2012-04-06 22:27:55 +00:00
|
|
|
xmlNodePtr theNode = [subNode _node];
|
|
|
|
xmlNodePtr prev = theNode->prev;
|
|
|
|
xmlNodePtr next = theNode->next;
|
2012-03-04 21:40:39 +00:00
|
|
|
|
2012-04-06 22:27:55 +00:00
|
|
|
if (theNode->type == XML_ELEMENT_NODE)
|
2012-03-01 06:11:30 +00:00
|
|
|
{
|
|
|
|
[(NSXMLElement *)subNode
|
|
|
|
normalizeAdjacentTextNodesPreservingCDATA:preserve];
|
|
|
|
}
|
2012-04-06 22:27:55 +00:00
|
|
|
else if (theNode->type == XML_TEXT_NODE
|
|
|
|
|| (theNode->type == XML_CDATA_SECTION_NODE && !preserve))
|
2012-02-20 03:40:15 +00:00
|
|
|
{
|
|
|
|
if (next && (next->type == XML_TEXT_NODE
|
2012-03-01 06:11:30 +00:00
|
|
|
|| (next->type == XML_CDATA_SECTION_NODE && !preserve)))
|
2012-02-20 03:40:15 +00:00
|
|
|
{
|
|
|
|
//combine node & node->next
|
2012-04-06 22:27:55 +00:00
|
|
|
joinTextNodes(theNode, theNode->next, nodesToDelete);
|
2012-02-20 03:40:15 +00:00
|
|
|
}
|
|
|
|
if (prev && (prev->type == XML_TEXT_NODE
|
2012-03-01 06:11:30 +00:00
|
|
|
|| (prev->type == XML_CDATA_SECTION_NODE && !preserve)))
|
2012-02-20 03:40:15 +00:00
|
|
|
{
|
2012-03-01 06:11:30 +00:00
|
|
|
/* combine node->prev & node
|
|
|
|
* join the text of both nodes
|
|
|
|
* assign the joined text to the earlier of the two
|
|
|
|
* nodes that has an ObjC object
|
|
|
|
* unlink the other node
|
|
|
|
* delete the other node's object (maybe add it to a
|
|
|
|
* list of nodes to delete when we're done? --
|
|
|
|
* or just set its node to null, and then remove it
|
|
|
|
* from our subNodes when we're done iterating it)
|
|
|
|
* (or maybe we need to turn it into an NSInvalidNode too??)
|
|
|
|
*/
|
2012-04-06 22:27:55 +00:00
|
|
|
joinTextNodes(theNode->prev, theNode, nodesToDelete);
|
2012-02-20 03:40:15 +00:00
|
|
|
}
|
2012-01-07 13:08:03 +00:00
|
|
|
|
2012-02-20 03:40:15 +00:00
|
|
|
}
|
2012-01-06 02:43:26 +00:00
|
|
|
}
|
2012-02-20 03:40:15 +00:00
|
|
|
if ([nodesToDelete count] > 0)
|
2012-01-07 13:08:03 +00:00
|
|
|
{
|
2012-02-20 03:40:15 +00:00
|
|
|
subEnum = [nodesToDelete objectEnumerator];
|
|
|
|
while ((subNode = [subEnum nextObject]))
|
|
|
|
{
|
2012-03-12 22:33:27 +00:00
|
|
|
[self _removeSubNode: subNode];
|
2012-02-20 03:40:15 +00:00
|
|
|
}
|
2012-01-07 13:08:03 +00:00
|
|
|
}
|
2012-02-20 03:40:15 +00:00
|
|
|
}
|
2012-01-06 12:22:30 +00:00
|
|
|
|
2009-02-09 16:16:11 +00:00
|
|
|
@end
|
|
|
|
|
2012-03-21 08:00:33 +00:00
|
|
|
#endif /* HAVE_LIBXML */
|