• R/O
  • SSH
  • HTTPS

poi-poi-capsule: Commit


Commit MetaInfo

Révision274 (tree)
l'heure2011-05-06 19:07:02
Auteurpoi-poi-capsule

Message de Log

kissxmlアップデート

Change Summary

Modification

--- trunk/0.2.X/KissXML/DDXMLDocument.m (nonexistent)
+++ trunk/0.2.X/KissXML/DDXMLDocument.m (revision 274)
@@ -0,0 +1,114 @@
1+#import "DDXMLPrivate.h"
2+#import "NSString+DDXML.h"
3+
4+
5+@implementation DDXMLDocument
6+
7+/**
8+ * Returns a DDXML wrapper object for the given primitive node.
9+ * The given node MUST be non-NULL and of the proper type.
10+**/
11++ (id)nodeWithDocPrimitive:(xmlDocPtr)doc freeOnDealloc:(BOOL)flag
12+{
13+ return [[[DDXMLDocument alloc] initWithDocPrimitive:doc freeOnDealloc:flag] autorelease];
14+}
15+
16+- (id)initWithDocPrimitive:(xmlDocPtr)doc freeOnDealloc:(BOOL)flag
17+{
18+ self = [super initWithPrimitive:(xmlKindPtr)doc freeOnDealloc:flag];
19+ return self;
20+}
21+
22++ (id)nodeWithPrimitive:(xmlKindPtr)kindPtr freeOnDealloc:(BOOL)flag
23+{
24+ // Promote initializers which use proper parameter types to enable compiler to catch more mistakes
25+ NSAssert(NO, @"Use nodeWithDocPrimitive:freeOnDealloc:");
26+
27+ return nil;
28+}
29+
30+- (id)initWithPrimitive:(xmlKindPtr)kindPtr freeOnDealloc:(BOOL)flag
31+{
32+ // Promote initializers which use proper parameter types to enable compiler to catch more mistakes.
33+ NSAssert(NO, @"Use initWithDocPrimitive:freeOnDealloc:");
34+
35+ [self release];
36+ return nil;
37+}
38+
39+/**
40+ * Initializes and returns a DDXMLDocument object created from an NSData object.
41+ *
42+ * Returns an initialized DDXMLDocument object, or nil if initialization fails
43+ * because of parsing errors or other reasons.
44+**/
45+- (id)initWithXMLString:(NSString *)string options:(NSUInteger)mask error:(NSError **)error
46+{
47+ return [self initWithData:[string dataUsingEncoding:NSUTF8StringEncoding]
48+ options:mask
49+ error:error];
50+}
51+
52+/**
53+ * Initializes and returns a DDXMLDocument object created from an NSData object.
54+ *
55+ * Returns an initialized DDXMLDocument object, or nil if initialization fails
56+ * because of parsing errors or other reasons.
57+**/
58+- (id)initWithData:(NSData *)data options:(NSUInteger)mask error:(NSError **)error
59+{
60+ if (data == nil || [data length] == 0)
61+ {
62+ if (error) *error = [NSError errorWithDomain:@"DDXMLErrorDomain" code:0 userInfo:nil];
63+
64+ [self release];
65+ return nil;
66+ }
67+
68+ // Even though xmlKeepBlanksDefault(0) is called in DDXMLNode's initialize method,
69+ // it has been documented that this call seems to get reset on the iPhone:
70+ // http://code.google.com/p/kissxml/issues/detail?id=8
71+ //
72+ // Therefore, we call it again here just to be safe.
73+ xmlKeepBlanksDefault(0);
74+
75+ xmlDocPtr doc = xmlParseMemory([data bytes], [data length]);
76+ if (doc == NULL)
77+ {
78+ if (error) *error = [NSError errorWithDomain:@"DDXMLErrorDomain" code:1 userInfo:nil];
79+
80+ [self release];
81+ return nil;
82+ }
83+
84+ return [self initWithDocPrimitive:doc freeOnDealloc:YES];
85+}
86+
87+/**
88+ * Returns the root element of the receiver.
89+**/
90+- (DDXMLElement *)rootElement
91+{
92+ xmlDocPtr doc = (xmlDocPtr)genericPtr;
93+
94+ // doc->children is a list containing possibly comments, DTDs, etc...
95+
96+ xmlNodePtr rootNode = xmlDocGetRootElement(doc);
97+
98+ if (rootNode != NULL)
99+ return [DDXMLElement nodeWithElementPrimitive:rootNode freeOnDealloc:NO];
100+ else
101+ return nil;
102+}
103+
104+- (NSData *)XMLData
105+{
106+ return [[self XMLString] dataUsingEncoding:NSUTF8StringEncoding];
107+}
108+
109+- (NSData *)XMLDataWithOptions:(NSUInteger)options
110+{
111+ return [[self XMLStringWithOptions:options] dataUsingEncoding:NSUTF8StringEncoding];
112+}
113+
114+@end
--- trunk/0.2.X/KissXML/DDXMLNode.h (nonexistent)
+++ trunk/0.2.X/KissXML/DDXMLNode.h (revision 274)
@@ -0,0 +1,136 @@
1+#import <Foundation/Foundation.h>
2+#import <libxml/tree.h>
3+
4+@class DDXMLDocument;
5+
6+
7+enum {
8+ DDXMLInvalidKind = 0,
9+ DDXMLDocumentKind = XML_DOCUMENT_NODE,
10+ DDXMLElementKind = XML_ELEMENT_NODE,
11+ DDXMLAttributeKind = XML_ATTRIBUTE_NODE,
12+ DDXMLNamespaceKind = XML_NAMESPACE_DECL,
13+ DDXMLProcessingInstructionKind = XML_PI_NODE,
14+ DDXMLCommentKind = XML_COMMENT_NODE,
15+ DDXMLTextKind = XML_TEXT_NODE,
16+ DDXMLDTDKind = XML_DTD_NODE,
17+ DDXMLEntityDeclarationKind = XML_ENTITY_DECL,
18+ DDXMLAttributeDeclarationKind = XML_ATTRIBUTE_DECL,
19+ DDXMLElementDeclarationKind = XML_ELEMENT_DECL,
20+ DDXMLNotationDeclarationKind = XML_NOTATION_NODE
21+};
22+typedef NSUInteger DDXMLNodeKind;
23+
24+enum {
25+ DDXMLNodeOptionsNone = 0,
26+ DDXMLNodeExpandEmptyElement = 1 << 1,
27+ DDXMLNodeCompactEmptyElement = 1 << 2,
28+ DDXMLNodePrettyPrint = 1 << 17,
29+};
30+
31+
32+//extern struct _xmlKind;
33+
34+
35+@interface DDXMLNode : NSObject <NSCopying>
36+{
37+ // Every DDXML object is simply a wrapper around an underlying libxml node
38+ struct _xmlKind *genericPtr;
39+
40+ // Root nodes free the underlying libxml node on dealloc.
41+ BOOL freeOnDealloc;
42+}
43+
44+//- (id)initWithKind:(DDXMLNodeKind)kind;
45+
46+//- (id)initWithKind:(DDXMLNodeKind)kind options:(NSUInteger)options;
47+
48+//+ (id)document;
49+
50+//+ (id)documentWithRootElement:(DDXMLElement *)element;
51+
52++ (id)elementWithName:(NSString *)name;
53+
54++ (id)elementWithName:(NSString *)name URI:(NSString *)URI;
55+
56++ (id)elementWithName:(NSString *)name stringValue:(NSString *)string;
57+
58++ (id)elementWithName:(NSString *)name children:(NSArray *)children attributes:(NSArray *)attributes;
59+
60++ (id)attributeWithName:(NSString *)name stringValue:(NSString *)stringValue;
61+
62++ (id)attributeWithName:(NSString *)name URI:(NSString *)URI stringValue:(NSString *)stringValue;
63+
64++ (id)namespaceWithName:(NSString *)name stringValue:(NSString *)stringValue;
65+
66++ (id)processingInstructionWithName:(NSString *)name stringValue:(NSString *)stringValue;
67+
68++ (id)commentWithStringValue:(NSString *)stringValue;
69+
70++ (id)textWithStringValue:(NSString *)stringValue;
71+
72+//+ (id)DTDNodeWithXMLString:(NSString *)string;
73+
74+#pragma mark --- Properties ---
75+
76+- (DDXMLNodeKind)kind;
77+
78+- (void)setName:(NSString *)name;
79+- (NSString *)name;
80+
81+//- (void)setObjectValue:(id)value;
82+//- (id)objectValue;
83+
84+- (void)setStringValue:(NSString *)string;
85+//- (void)setStringValue:(NSString *)string resolvingEntities:(BOOL)resolve;
86+- (NSString *)stringValue;
87+
88+#pragma mark --- Tree Navigation ---
89+
90+- (NSUInteger)index;
91+
92+- (NSUInteger)level;
93+
94+- (DDXMLDocument *)rootDocument;
95+
96+- (DDXMLNode *)parent;
97+- (NSUInteger)childCount;
98+- (NSArray *)children;
99+- (DDXMLNode *)childAtIndex:(NSUInteger)index;
100+
101+- (DDXMLNode *)previousSibling;
102+- (DDXMLNode *)nextSibling;
103+
104+- (DDXMLNode *)previousNode;
105+- (DDXMLNode *)nextNode;
106+
107+- (void)detach;
108+
109+- (NSString *)XPath;
110+
111+#pragma mark --- QNames ---
112+
113+- (NSString *)localName;
114+- (NSString *)prefix;
115+
116+- (void)setURI:(NSString *)URI;
117+- (NSString *)URI;
118+
119++ (NSString *)localNameForName:(NSString *)name;
120++ (NSString *)prefixForName:(NSString *)name;
121+//+ (DDXMLNode *)predefinedNamespaceForPrefix:(NSString *)name;
122+
123+#pragma mark --- Output ---
124+
125+- (NSString *)description;
126+- (NSString *)XMLString;
127+- (NSString *)XMLStringWithOptions:(NSUInteger)options;
128+//- (NSString *)canonicalXMLStringPreservingComments:(BOOL)comments;
129+
130+#pragma mark --- XPath/XQuery ---
131+
132+- (NSArray *)nodesForXPath:(NSString *)xpath error:(NSError **)error;
133+//- (NSArray *)objectsForXQuery:(NSString *)xquery constants:(NSDictionary *)constants error:(NSError **)error;
134+//- (NSArray *)objectsForXQuery:(NSString *)xquery error:(NSError **)error;
135+
136+@end
--- trunk/0.2.X/KissXML/Categories/NSString+DDXML.h (nonexistent)
+++ trunk/0.2.X/KissXML/Categories/NSString+DDXML.h (revision 274)
@@ -0,0 +1,14 @@
1+#import <Foundation/Foundation.h>
2+#import <libxml/tree.h>
3+
4+
5+@interface NSString (DDXML)
6+
7+/**
8+ * xmlChar - A basic replacement for char, a byte in a UTF-8 encoded string.
9+**/
10+- (const xmlChar *)xmlChar;
11+
12+- (NSString *)stringByTrimming;
13+
14+@end
--- trunk/0.2.X/KissXML/Categories/NSString+DDXML.m (nonexistent)
+++ trunk/0.2.X/KissXML/Categories/NSString+DDXML.m (revision 274)
@@ -0,0 +1,29 @@
1+#import "NSString+DDXML.h"
2+
3+
4+@implementation NSString (DDXML)
5+
6+- (const xmlChar *)xmlChar
7+{
8+ return (const xmlChar *)[self UTF8String];
9+}
10+
11+#ifdef GNUSTEP
12+- (NSString *)stringByTrimming
13+{
14+ return [self stringByTrimmingSpaces];
15+}
16+#else
17+- (NSString *)stringByTrimming
18+{
19+ NSMutableString *mStr = [self mutableCopy];
20+ CFStringTrimWhitespace((CFMutableStringRef)mStr);
21+
22+ NSString *result = [mStr copy];
23+
24+ [mStr release];
25+ return [result autorelease];
26+}
27+#endif
28+
29+@end
--- trunk/0.2.X/KissXML/DDXMLElement.h (nonexistent)
+++ trunk/0.2.X/KissXML/DDXMLElement.h (revision 274)
@@ -0,0 +1,49 @@
1+#import <Foundation/Foundation.h>
2+#import "DDXMLNode.h"
3+
4+
5+@interface DDXMLElement : DDXMLNode
6+{
7+}
8+
9+- (id)initWithName:(NSString *)name;
10+- (id)initWithName:(NSString *)name URI:(NSString *)URI;
11+- (id)initWithName:(NSString *)name stringValue:(NSString *)string;
12+- (id)initWithXMLString:(NSString *)string error:(NSError **)error;
13+
14+#pragma mark --- Elements by name ---
15+
16+- (NSArray *)elementsForName:(NSString *)name;
17+- (NSArray *)elementsForLocalName:(NSString *)localName URI:(NSString *)URI;
18+
19+#pragma mark --- Attributes ---
20+
21+- (void)addAttribute:(DDXMLNode *)attribute;
22+- (void)removeAttributeForName:(NSString *)name;
23+- (void)setAttributes:(NSArray *)attributes;
24+//- (void)setAttributesAsDictionary:(NSDictionary *)attributes;
25+- (NSArray *)attributes;
26+- (DDXMLNode *)attributeForName:(NSString *)name;
27+//- (DDXMLNode *)attributeForLocalName:(NSString *)localName URI:(NSString *)URI;
28+
29+#pragma mark --- Namespaces ---
30+
31+- (void)addNamespace:(DDXMLNode *)aNamespace;
32+- (void)removeNamespaceForPrefix:(NSString *)name;
33+- (void)setNamespaces:(NSArray *)namespaces;
34+- (NSArray *)namespaces;
35+- (DDXMLNode *)namespaceForPrefix:(NSString *)prefix;
36+- (DDXMLNode *)resolveNamespaceForName:(NSString *)name;
37+- (NSString *)resolvePrefixForNamespaceURI:(NSString *)namespaceURI;
38+
39+#pragma mark --- Children ---
40+
41+- (void)insertChild:(DDXMLNode *)child atIndex:(NSUInteger)index;
42+//- (void)insertChildren:(NSArray *)children atIndex:(NSUInteger)index;
43+- (void)removeChildAtIndex:(NSUInteger)index;
44+- (void)setChildren:(NSArray *)children;
45+- (void)addChild:(DDXMLNode *)child;
46+//- (void)replaceChildAtIndex:(NSUInteger)index withNode:(DDXMLNode *)node;
47+//- (void)normalizeAdjacentTextNodesPreservingCDATA:(BOOL)preserve;
48+
49+@end
--- trunk/0.2.X/KissXML/DDXMLNode.m (nonexistent)
+++ trunk/0.2.X/KissXML/DDXMLNode.m (revision 274)
@@ -0,0 +1,1858 @@
1+#import "DDXMLPrivate.h"
2+#import "NSString+DDXML.h"
3+
4+#import <libxml/xpath.h>
5+#import <libxml/xpathInternals.h>
6+
7+
8+@implementation DDXMLNode
9+
10+static void MyErrorHandler(void * userData, xmlErrorPtr error);
11+
12++ (void)initialize
13+{
14+ static BOOL initialized = NO;
15+ if (!initialized)
16+ {
17+ initialized = YES;
18+
19+ // Redirect error output to our own function (don't clog up the console)
20+ initGenericErrorDefaultFunc(NULL);
21+ xmlSetStructuredErrorFunc(NULL, MyErrorHandler);
22+
23+ // Tell libxml not to keep ignorable whitespace (such as node indentation, formatting, etc).
24+ // NSXML ignores such whitespace.
25+ // This also has the added benefit of taking up less RAM when parsing formatted XML documents.
26+ xmlKeepBlanksDefault(0);
27+ }
28+}
29+
30++ (id)elementWithName:(NSString *)name
31+{
32+ return [[[DDXMLElement alloc] initWithName:name] autorelease];
33+}
34+
35++ (id)elementWithName:(NSString *)name stringValue:(NSString *)string
36+{
37+ return [[[DDXMLElement alloc] initWithName:name stringValue:string] autorelease];
38+}
39+
40++ (id)elementWithName:(NSString *)name children:(NSArray *)children attributes:(NSArray *)attributes
41+{
42+ DDXMLElement *result = [[[DDXMLElement alloc] initWithName:name] autorelease];
43+ [result setChildren:children];
44+ [result setAttributes:attributes];
45+
46+ return result;
47+}
48+
49++ (id)elementWithName:(NSString *)name URI:(NSString *)URI
50+{
51+ return [[[DDXMLElement alloc] initWithName:name URI:URI] autorelease];
52+}
53+
54++ (id)attributeWithName:(NSString *)name stringValue:(NSString *)stringValue
55+{
56+ xmlAttrPtr attr = xmlNewProp(NULL, [name xmlChar], [stringValue xmlChar]);
57+
58+ if (attr == NULL) return nil;
59+
60+ return [[[DDXMLAttributeNode alloc] initWithAttrPrimitive:attr freeOnDealloc:YES] autorelease];
61+}
62+
63++ (id)attributeWithName:(NSString *)name URI:(NSString *)URI stringValue:(NSString *)stringValue
64+{
65+ xmlAttrPtr attr = xmlNewProp(NULL, [name xmlChar], [stringValue xmlChar]);
66+
67+ if (attr == NULL) return nil;
68+
69+ DDXMLAttributeNode *result = [[DDXMLAttributeNode alloc] initWithAttrPrimitive:attr freeOnDealloc:YES];
70+ [result setURI:URI];
71+
72+ return [result autorelease];
73+}
74+
75++ (id)namespaceWithName:(NSString *)name stringValue:(NSString *)stringValue
76+{
77+ // If the user passes a nil or empty string name, they are trying to create a default namespace
78+ const xmlChar *xmlName = [name length] > 0 ? [name xmlChar] : NULL;
79+
80+ xmlNsPtr ns = xmlNewNs(NULL, [stringValue xmlChar], xmlName);
81+
82+ if (ns == NULL) return nil;
83+
84+ return [[[DDXMLNamespaceNode alloc] initWithNsPrimitive:ns nsParent:NULL freeOnDealloc:YES] autorelease];
85+}
86+
87++ (id)processingInstructionWithName:(NSString *)name stringValue:(NSString *)stringValue
88+{
89+ xmlNodePtr procInst = xmlNewPI([name xmlChar], [stringValue xmlChar]);
90+
91+ if (procInst == NULL) return nil;
92+
93+ return [[[DDXMLNode alloc] initWithPrimitive:(xmlKindPtr)procInst freeOnDealloc:YES] autorelease];
94+}
95+
96++ (id)commentWithStringValue:(NSString *)stringValue
97+{
98+ xmlNodePtr comment = xmlNewComment([stringValue xmlChar]);
99+
100+ if (comment == NULL) return nil;
101+
102+ return [[[DDXMLNode alloc] initWithPrimitive:(xmlKindPtr)comment freeOnDealloc:YES] autorelease];
103+}
104+
105++ (id)textWithStringValue:(NSString *)stringValue
106+{
107+ xmlNodePtr text = xmlNewText([stringValue xmlChar]);
108+
109+ if (text == NULL) return nil;
110+
111+ return [[[DDXMLNode alloc] initWithPrimitive:(xmlKindPtr)text freeOnDealloc:YES] autorelease];
112+}
113+
114+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
115+#pragma mark Init, Dealloc
116+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
117+
118++ (id)nodeWithUnknownPrimitive:(xmlKindPtr)kindPtr freeOnDealloc:(BOOL)flag
119+{
120+ if (kindPtr->type == XML_DOCUMENT_NODE)
121+ {
122+ return [DDXMLDocument nodeWithDocPrimitive:(xmlDocPtr)kindPtr freeOnDealloc:flag];
123+ }
124+ else if (kindPtr->type == XML_ELEMENT_NODE)
125+ {
126+ return [DDXMLElement nodeWithElementPrimitive:(xmlNodePtr)kindPtr freeOnDealloc:flag];
127+ }
128+ else if (kindPtr->type == XML_NAMESPACE_DECL)
129+ {
130+ // Todo: This may be a problem...
131+
132+ return [DDXMLNamespaceNode nodeWithNsPrimitive:(xmlNsPtr)kindPtr nsParent:NULL freeOnDealloc:flag];
133+ }
134+ else if (kindPtr->type == XML_ATTRIBUTE_NODE)
135+ {
136+ return [DDXMLAttributeNode nodeWithAttrPrimitive:(xmlAttrPtr)kindPtr freeOnDealloc:flag];
137+ }
138+ else
139+ {
140+ return [DDXMLNode nodeWithPrimitive:kindPtr freeOnDealloc:flag];
141+ }
142+}
143+
144+/**
145+ * Returns a DDXML wrapper object for the given primitive node.
146+ * The given node MUST be non-NULL and of the proper type.
147+**/
148++ (id)nodeWithPrimitive:(xmlKindPtr)kindPtr freeOnDealloc:(BOOL)flag
149+{
150+ return [[[DDXMLNode alloc] initWithPrimitive:kindPtr freeOnDealloc:flag] autorelease];
151+}
152+
153+/**
154+ * Returns a DDXML wrapper object for the given primitive node.
155+ * The given node MUST be non-NULL and of the proper type.
156+**/
157+- (id)initWithPrimitive:(xmlKindPtr)kindPtr freeOnDealloc:(BOOL)flag
158+{
159+ if ((self = [super init]))
160+ {
161+ genericPtr = kindPtr;
162+ freeOnDealloc = flag;
163+ }
164+ return self;
165+}
166+
167+- (void)dealloc
168+{
169+ if (freeOnDealloc)
170+ {
171+ if (IsXmlNsPtr(genericPtr))
172+ {
173+ xmlFreeNs((xmlNsPtr)genericPtr);
174+ }
175+ else if (IsXmlAttrPtr(genericPtr))
176+ {
177+ xmlFreeProp((xmlAttrPtr)genericPtr);
178+ }
179+ else if (IsXmlDtdPtr(genericPtr))
180+ {
181+ xmlFreeDtd((xmlDtdPtr)genericPtr);
182+ }
183+ else if (IsXmlDocPtr(genericPtr))
184+ {
185+ xmlFreeDoc((xmlDocPtr)genericPtr);
186+ }
187+ else if (IsXmlNodePtr(genericPtr))
188+ {
189+ xmlFreeNode((xmlNodePtr)genericPtr);
190+ }
191+ else
192+ {
193+ NSAssert1(NO, @"Cannot free unknown node type: %i", ((xmlKindPtr)genericPtr)->type);
194+ }
195+ }
196+ [super dealloc];
197+}
198+
199+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
200+#pragma mark Copying
201+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
202+
203+- (id)copyWithZone:(NSZone *)zone
204+{
205+ if (IsXmlDocPtr(genericPtr))
206+ {
207+ xmlDocPtr copyDocPtr = xmlCopyDoc((xmlDocPtr)genericPtr, 1);
208+
209+ if (copyDocPtr == NULL) return nil;
210+
211+ return [[DDXMLDocument alloc] initWithDocPrimitive:copyDocPtr freeOnDealloc:YES];
212+ }
213+
214+ if (IsXmlNodePtr(genericPtr))
215+ {
216+ xmlNodePtr copyNodePtr = xmlCopyNode((xmlNodePtr)genericPtr, 1);
217+
218+ if (copyNodePtr == NULL) return nil;
219+
220+ if ([self isKindOfClass:[DDXMLElement class]])
221+ return [[DDXMLElement alloc] initWithElementPrimitive:copyNodePtr freeOnDealloc:YES];
222+ else
223+ return [[DDXMLNode alloc] initWithPrimitive:(xmlKindPtr)copyNodePtr freeOnDealloc:YES];
224+ }
225+
226+ if (IsXmlAttrPtr(genericPtr))
227+ {
228+ xmlAttrPtr copyAttrPtr = xmlCopyProp(NULL, (xmlAttrPtr)genericPtr);
229+
230+ if (copyAttrPtr == NULL) return nil;
231+
232+ return [[DDXMLAttributeNode alloc] initWithAttrPrimitive:copyAttrPtr freeOnDealloc:YES];
233+ }
234+
235+ if (IsXmlNsPtr(genericPtr))
236+ {
237+ xmlNsPtr copyNsPtr = xmlCopyNamespace((xmlNsPtr)genericPtr);
238+
239+ if (copyNsPtr == NULL) return nil;
240+
241+ return [[DDXMLNamespaceNode alloc] initWithNsPrimitive:copyNsPtr nsParent:NULL freeOnDealloc:YES];
242+ }
243+
244+ if (IsXmlDtdPtr(genericPtr))
245+ {
246+ xmlDtdPtr copyDtdPtr = xmlCopyDtd((xmlDtdPtr)genericPtr);
247+
248+ if (copyDtdPtr == NULL) return nil;
249+
250+ return [[DDXMLNode alloc] initWithPrimitive:(xmlKindPtr)copyDtdPtr freeOnDealloc:YES];
251+ }
252+
253+ return nil;
254+}
255+
256+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
257+#pragma mark Properties
258+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
259+
260+- (DDXMLNodeKind)kind
261+{
262+ if (genericPtr != NULL)
263+ return genericPtr->type;
264+ else
265+ return DDXMLInvalidKind;
266+}
267+
268+- (void)setName:(NSString *)name
269+{
270+ // Note: DDXMLNamespaceNode overrides this method
271+
272+ // The xmlNodeSetName function works for both nodes and attributes
273+ xmlNodeSetName((xmlNodePtr)genericPtr, [name xmlChar]);
274+}
275+
276+- (NSString *)name
277+{
278+ // Note: DDXMLNamespaceNode overrides this method
279+
280+ const char *name = (const char *)((xmlStdPtr)genericPtr)->name;
281+
282+ if (name == NULL)
283+ return nil;
284+ else
285+ return [NSString stringWithUTF8String:name];
286+}
287+
288+- (void)setStringValue:(NSString *)string
289+{
290+ // Note: DDXMLNamespaceNode overrides this method
291+ // Note: DDXMLAttributeNode overrides this method
292+
293+ if (IsXmlNodePtr(genericPtr))
294+ {
295+ xmlStdPtr node = (xmlStdPtr)genericPtr;
296+
297+ // Setting the content of a node erases any existing child nodes.
298+ // Therefore, we need to remove them properly first.
299+ [[self class] removeAllChildrenFromNode:(xmlNodePtr)node];
300+
301+ xmlChar *escapedString = xmlEncodeSpecialChars(node->doc, [string xmlChar]);
302+ xmlNodeSetContent((xmlNodePtr)node, escapedString);
303+ xmlFree(escapedString);
304+ }
305+}
306+
307+/**
308+ * Returns the content of the receiver as a string value.
309+ *
310+ * If the receiver is a node object of element kind, the content is that of any text-node children.
311+ * This method recursively visits elements nodes and concatenates their text nodes in document order with
312+ * no intervening spaces.
313+**/
314+- (NSString *)stringValue
315+{
316+ // Note: DDXMLNamespaceNode overrides this method
317+ // Note: DDXMLAttributeNode overrides this method
318+
319+ if (IsXmlNodePtr(genericPtr))
320+ {
321+ xmlChar *content = xmlNodeGetContent((xmlNodePtr)genericPtr);
322+
323+ NSString *result = [NSString stringWithUTF8String:(const char *)content];
324+
325+ xmlFree(content);
326+ return result;
327+ }
328+
329+ return nil;
330+}
331+
332+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
333+#pragma mark Tree Navigation
334+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
335+
336+/**
337+ * Returns the index of the receiver identifying its position relative to its sibling nodes.
338+ * The first child node of a parent has an index of zero.
339+**/
340+- (NSUInteger)index
341+{
342+ // Note: DDXMLNamespaceNode overrides this method
343+
344+ NSUInteger result = 0;
345+
346+ xmlStdPtr node = ((xmlStdPtr)genericPtr)->prev;
347+ while (node != NULL)
348+ {
349+ result++;
350+ node = node->prev;
351+ }
352+
353+ return result;
354+}
355+
356+/**
357+ * Returns the nesting level of the receiver within the tree hierarchy.
358+ * The root element of a document has a nesting level of one.
359+**/
360+- (NSUInteger)level
361+{
362+ // Note: DDXMLNamespaceNode overrides this method
363+
364+ NSUInteger result = 0;
365+
366+ xmlNodePtr currentNode = ((xmlStdPtr)genericPtr)->parent;
367+ while (currentNode != NULL)
368+ {
369+ result++;
370+ currentNode = currentNode->parent;
371+ }
372+
373+ return result;
374+}
375+
376+/**
377+ * Returns the DDXMLDocument object containing the root element and representing the XML document as a whole.
378+ * If the receiver is a standalone node (that is, a node at the head of a detached branch of the tree), this
379+ * method returns nil.
380+**/
381+- (DDXMLDocument *)rootDocument
382+{
383+ // Note: DDXMLNamespaceNode overrides this method
384+
385+ xmlStdPtr node = (xmlStdPtr)genericPtr;
386+
387+ if (node == NULL || node->doc == NULL)
388+ return nil;
389+ else
390+ return [DDXMLDocument nodeWithDocPrimitive:node->doc freeOnDealloc:NO];
391+}
392+
393+/**
394+ * Returns the parent node of the receiver.
395+ *
396+ * Document nodes and standalone nodes (that is, the root of a detached branch of a tree) have no parent, and
397+ * sending this message to them returns nil. A one-to-one relationship does not always exists between a parent and
398+ * its children; although a namespace or attribute node cannot be a child, it still has a parent element.
399+**/
400+- (DDXMLNode *)parent
401+{
402+ // Note: DDXMLNamespaceNode overrides this method
403+
404+ xmlStdPtr node = (xmlStdPtr)genericPtr;
405+
406+ if (node->parent == NULL)
407+ return nil;
408+ else
409+ return [DDXMLNode nodeWithUnknownPrimitive:(xmlKindPtr)node->parent freeOnDealloc:NO];
410+}
411+
412+/**
413+ * Returns the number of child nodes the receiver has.
414+ * For performance reasons, use this method instead of getting the count from the array returned by children.
415+**/
416+- (NSUInteger)childCount
417+{
418+ // Note: DDXMLNamespaceNode overrides this method
419+
420+ if (!IsXmlDocPtr(genericPtr) && !IsXmlNodePtr(genericPtr) && !IsXmlDtdPtr(genericPtr))
421+ {
422+ return 0;
423+ }
424+
425+ NSUInteger result = 0;
426+
427+ xmlNodePtr child = ((xmlStdPtr)genericPtr)->children;
428+ while (child != NULL)
429+ {
430+ result++;
431+ child = child->next;
432+ }
433+
434+ return result;
435+}
436+
437+/**
438+ * Returns an immutable array containing the child nodes of the receiver (as DDXMLNode objects).
439+**/
440+- (NSArray *)children
441+{
442+ // Note: DDXMLNamespaceNode overrides this method
443+
444+ if (!IsXmlDocPtr(genericPtr) && !IsXmlNodePtr(genericPtr) && !IsXmlDtdPtr(genericPtr))
445+ {
446+ return nil;
447+ }
448+
449+ NSMutableArray *result = [NSMutableArray array];
450+
451+ xmlNodePtr child = ((xmlStdPtr)genericPtr)->children;
452+ while (child != NULL)
453+ {
454+ [result addObject:[DDXMLNode nodeWithUnknownPrimitive:(xmlKindPtr)child freeOnDealloc:NO]];
455+
456+ child = child->next;
457+ }
458+
459+ return [[result copy] autorelease];
460+}
461+
462+/**
463+ * Returns the child node of the receiver at the specified location.
464+ * Returns a DDXMLNode object or nil if the receiver has no children.
465+ *
466+ * If the receive has children and index is out of bounds, an exception is raised.
467+ *
468+ * The receiver should be a DDXMLNode object representing a document, element, or document type declaration.
469+ * The returned node object can represent an element, comment, text, or processing instruction.
470+**/
471+- (DDXMLNode *)childAtIndex:(NSUInteger)index
472+{
473+ // Note: DDXMLNamespaceNode overrides this method
474+
475+ if (!IsXmlDocPtr(genericPtr) && !IsXmlNodePtr(genericPtr) && !IsXmlDtdPtr(genericPtr))
476+ {
477+ return nil;
478+ }
479+
480+ NSUInteger i = 0;
481+
482+ xmlNodePtr child = ((xmlStdPtr)genericPtr)->children;
483+
484+ if (child == NULL)
485+ {
486+ // NSXML doesn't raise an exception if there are no children
487+ return nil;
488+ }
489+
490+ while (child != NULL)
491+ {
492+ if (i == index)
493+ {
494+ return [DDXMLNode nodeWithUnknownPrimitive:(xmlKindPtr)child freeOnDealloc:NO];
495+ }
496+
497+ i++;
498+ child = child->next;
499+ }
500+
501+ // NSXML version uses this same assertion
502+ DDXMLAssert(NO, @"index (%u) beyond bounds (%u)", (unsigned)index, (unsigned)i);
503+
504+ return nil;
505+}
506+
507+/**
508+ * Returns the previous DDXMLNode object that is a sibling node to the receiver.
509+ *
510+ * This object will have an index value that is one less than the receiverユs.
511+ * If there are no more previous siblings (that is, other child nodes of the receiverユs parent) the method returns nil.
512+**/
513+- (DDXMLNode *)previousSibling
514+{
515+ // Note: DDXMLNamespaceNode overrides this method
516+
517+ xmlStdPtr node = (xmlStdPtr)genericPtr;
518+
519+ if (node->prev == NULL)
520+ return nil;
521+ else
522+ return [DDXMLNode nodeWithUnknownPrimitive:(xmlKindPtr)node->prev freeOnDealloc:NO];
523+}
524+
525+/**
526+ * Returns the next DDXMLNode object that is a sibling node to the receiver.
527+ *
528+ * This object will have an index value that is one more than the receiverユs.
529+ * If there are no more subsequent siblings (that is, other child nodes of the receiverユs parent) the
530+ * method returns nil.
531+**/
532+- (DDXMLNode *)nextSibling
533+{
534+ // Note: DDXMLNamespaceNode overrides this method
535+
536+ xmlStdPtr node = (xmlStdPtr)genericPtr;
537+
538+ if (node->next == NULL)
539+ return nil;
540+ else
541+ return [DDXMLNode nodeWithUnknownPrimitive:(xmlKindPtr)node->next freeOnDealloc:NO];
542+}
543+
544+/**
545+ * Returns the previous DDXMLNode object in document order.
546+ *
547+ * You use this method to メwalkモ backward through the tree structure representing an XML document or document section.
548+ * (Use nextNode to traverse the tree in the opposite direction.) Document order is the natural order that XML
549+ * constructs appear in markup text. If you send this message to the first node in the tree (that is, the root element),
550+ * nil is returned. DDXMLNode bypasses namespace and attribute nodes when it traverses a tree in document order.
551+**/
552+- (DDXMLNode *)previousNode
553+{
554+ // Note: DDXMLNamespaceNode overrides this method
555+ // Note: DDXMLAttributeNode overrides this method
556+
557+ // If the node has a previous sibling,
558+ // then we need the last child of the last child of the last child etc
559+
560+ // Note: Try to accomplish this task without creating dozens of intermediate wrapper objects
561+
562+ xmlStdPtr node = (xmlStdPtr)genericPtr;
563+ xmlStdPtr previousSibling = node->prev;
564+
565+ if (previousSibling != NULL)
566+ {
567+ if (previousSibling->last != NULL)
568+ {
569+ xmlNodePtr lastChild = previousSibling->last;
570+ while (lastChild->last != NULL)
571+ {
572+ lastChild = lastChild->last;
573+ }
574+
575+ return [DDXMLNode nodeWithUnknownPrimitive:(xmlKindPtr)lastChild freeOnDealloc:NO];
576+ }
577+ else
578+ {
579+ // The previous sibling has no children, so the previous node is simply the previous sibling
580+ return [DDXMLNode nodeWithUnknownPrimitive:(xmlKindPtr)previousSibling freeOnDealloc:NO];
581+ }
582+ }
583+
584+ // If there are no previous siblings, then the previous node is simply the parent
585+
586+ // Note: rootNode.parent == docNode
587+
588+ if (node->parent == NULL || node->parent->type == XML_DOCUMENT_NODE)
589+ return nil;
590+ else
591+ return [DDXMLNode nodeWithUnknownPrimitive:(xmlKindPtr)node->parent freeOnDealloc:NO];
592+}
593+
594+/**
595+ * Returns the next DDXMLNode object in document order.
596+ *
597+ * You use this method to メwalkモ forward through the tree structure representing an XML document or document section.
598+ * (Use previousNode to traverse the tree in the opposite direction.) Document order is the natural order that XML
599+ * constructs appear in markup text. If you send this message to the last node in the tree, nil is returned.
600+ * DDXMLNode bypasses namespace and attribute nodes when it traverses a tree in document order.
601+**/
602+- (DDXMLNode *)nextNode
603+{
604+ // Note: DDXMLNamespaceNode overrides this method
605+ // Note: DDXMLAttributeNode overrides this method
606+
607+ // If the node has children, then next node is the first child
608+ DDXMLNode *firstChild = [self childAtIndex:0];
609+ if (firstChild)
610+ return firstChild;
611+
612+ // If the node has a next sibling, then next node is the same as next sibling
613+
614+ DDXMLNode *nextSibling = [self nextSibling];
615+ if (nextSibling)
616+ return nextSibling;
617+
618+ // There are no children, and no more siblings, so we need to get the next sibling of the parent.
619+ // If that is nil, we need to get the next sibling of the grandparent, etc.
620+
621+ // Note: Try to accomplish this task without creating dozens of intermediate wrapper objects
622+
623+ xmlNodePtr parent = ((xmlStdPtr)genericPtr)->parent;
624+ while (parent != NULL)
625+ {
626+ xmlNodePtr parentNextSibling = parent->next;
627+ if (parentNextSibling != NULL)
628+ return [DDXMLNode nodeWithUnknownPrimitive:(xmlKindPtr)parentNextSibling freeOnDealloc:NO];
629+ else
630+ parent = parent->parent;
631+ }
632+
633+ return nil;
634+}
635+
636+/**
637+ * Detaches the receiver from its parent node.
638+ *
639+ * This method is applicable to DDXMLNode objects representing elements, text, comments, processing instructions,
640+ * attributes, and namespaces. Once the node object is detached, you can add it as a child node of another parent.
641+**/
642+- (void)detach
643+{
644+ // Note: DDXMLNamespaceNode overrides this method
645+ // Note: DDXMLAttributeNode overrides this method
646+
647+ xmlStdPtr node = (xmlStdPtr)genericPtr;
648+
649+ if (node->parent != NULL)
650+ {
651+ if (IsXmlNodePtr(genericPtr))
652+ {
653+ [[self class] detachChild:(xmlNodePtr)node fromNode:node->parent];
654+ freeOnDealloc = YES;
655+ }
656+ }
657+}
658+
659+- (xmlStdPtr)XPathPreProcess:(NSMutableString *)result
660+{
661+ // Note: DDXMLNamespaceNode overrides this method
662+ // Note: DDXMLAttributeNode overrides this method
663+
664+ return (xmlStdPtr)genericPtr;
665+}
666+
667+- (NSString *)XPath
668+{
669+ NSMutableString *result = [NSMutableString stringWithCapacity:25];
670+
671+ // Examples:
672+ // /rootElement[1]/subElement[4]/thisNode[2]
673+ // topElement/thisNode[2]
674+
675+ xmlStdPtr node = [self XPathPreProcess:result];
676+
677+ // Note: rootNode.parent == docNode
678+
679+ while ((node != NULL) && (node->type != XML_DOCUMENT_NODE))
680+ {
681+ if ((node->parent == NULL) && (node->doc == NULL))
682+ {
683+ // We're at the top of the heirarchy, and there is no xml document.
684+ // Thus we don't use a leading '/', and we don't need an index.
685+
686+ [result insertString:[NSString stringWithFormat:@"%s", node->name] atIndex:0];
687+ }
688+ else
689+ {
690+ // Find out what index this node is.
691+ // If it's the first node with this name, the index is 1.
692+ // If there are previous siblings with the same name, the index is greater than 1.
693+
694+ int index = 1;
695+ xmlStdPtr prevNode = node->prev;
696+
697+ while (prevNode != NULL)
698+ {
699+ if (xmlStrEqual(node->name, prevNode->name))
700+ {
701+ index++;
702+ }
703+ prevNode = prevNode->prev;
704+ }
705+
706+ [result insertString:[NSString stringWithFormat:@"/%s[%i]", node->name, index] atIndex:0];
707+ }
708+
709+ node = (xmlStdPtr)node->parent;
710+ }
711+
712+ return [[result copy] autorelease];
713+}
714+
715+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
716+#pragma mark QNames
717+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
718+
719+/**
720+ * Returns the local name of the receiver.
721+ *
722+ * The local name is the part of a node name that follows a namespace-qualifying colon or the full name if
723+ * there is no colon. For example, メchapterモ is the local name in the qualified name メacme:chapterモ.
724+**/
725+- (NSString *)localName
726+{
727+ // Note: DDXMLNamespaceNode overrides this method
728+
729+ return [[self class] localNameForName:[self name]];
730+}
731+
732+/**
733+ * Returns the prefix of the receiverユs name.
734+ *
735+ * The prefix is the part of a namespace-qualified name that precedes the colon.
736+ * For example, メacmeモ is the local name in the qualified name メacme:chapterモ.
737+ * This method returns an empty string if the receiverユs name is not qualified by a namespace.
738+**/
739+- (NSString *)prefix
740+{
741+ // Note: DDXMLNamespaceNode overrides this method
742+
743+ return [[self class] prefixForName:[self name]];
744+}
745+
746+/**
747+ * Sets the URI identifying the source of this document.
748+ * Pass nil to remove the current URI.
749+**/
750+- (void)setURI:(NSString *)URI
751+{
752+ // Note: DDXMLNamespaceNode overrides this method
753+ // Note: DDXMLAttributeNode overrides this method
754+
755+ if (IsXmlNodePtr(genericPtr))
756+ {
757+ xmlNodePtr node = (xmlNodePtr)genericPtr;
758+ if (node->ns != NULL)
759+ {
760+ [[self class] removeNamespace:node->ns fromNode:node];
761+ }
762+
763+ if (URI)
764+ {
765+ // Create a new xmlNsPtr, add it to the nsDef list, and make ns point to it
766+ xmlNsPtr ns = xmlNewNs(NULL, [URI xmlChar], NULL);
767+ ns->next = node->nsDef;
768+ node->nsDef = ns;
769+ node->ns = ns;
770+ }
771+ }
772+}
773+
774+/**
775+ * Returns the URI associated with the receiver.
776+ *
777+ * A nodeユs URI is derived from its namespace or a documentユs URI; for documents, the URI comes either from the
778+ * parsed XML or is explicitly set. You cannot change the URI for a particular node other for than a namespace
779+ * or document node.
780+**/
781+- (NSString *)URI
782+{
783+ // Note: DDXMLNamespaceNode overrides this method
784+ // Note: DDXMLAttributeNode overrides this method
785+
786+ if (IsXmlNodePtr(genericPtr))
787+ {
788+ xmlNodePtr node = (xmlNodePtr)genericPtr;
789+ if (node->ns != NULL)
790+ {
791+ return [NSString stringWithUTF8String:((const char *)node->ns->href)];
792+ }
793+ }
794+
795+ return nil;
796+}
797+
798+/**
799+ * Returns the local name from the specified qualified name.
800+ *
801+ * Examples:
802+ * "a:node" -> "node"
803+ * "a:a:node" -> "a:node"
804+ * "node" -> "node"
805+ * nil - > nil
806+**/
807++ (NSString *)localNameForName:(NSString *)name
808+{
809+ if (name)
810+ {
811+ NSRange range = [name rangeOfString:@":"];
812+
813+ if (range.length != 0)
814+ return [name substringFromIndex:(range.location + range.length)];
815+ else
816+ return name;
817+ }
818+ return nil;
819+}
820+
821+/**
822+ * Extracts the prefix from the given name.
823+ * If name is nil, or has no prefix, an empty string is returned.
824+ *
825+ * Examples:
826+ * "a:deusty.com" -> "a"
827+ * "a:a:deusty.com" -> "a"
828+ * "node" -> ""
829+ * nil -> ""
830+**/
831++ (NSString *)prefixForName:(NSString *)name
832+{
833+ if (name)
834+ {
835+ NSRange range = [name rangeOfString:@":"];
836+
837+ if (range.length != 0)
838+ {
839+ return [name substringToIndex:range.location];
840+ }
841+ }
842+ return @"";
843+}
844+
845+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
846+#pragma mark Output
847+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
848+
849+- (NSString *)description
850+{
851+ return [self XMLStringWithOptions:0];
852+}
853+
854+- (NSString *)XMLString
855+{
856+ // Todo: Test XMLString for namespace node
857+ return [self XMLStringWithOptions:0];
858+}
859+
860+- (NSString *)XMLStringWithOptions:(NSUInteger)options
861+{
862+ // xmlSaveNoEmptyTags:
863+ // Global setting, asking the serializer to not output empty tags
864+ // as <empty/> but <empty></empty>. those two forms are undistinguishable
865+ // once parsed.
866+ // Disabled by default
867+
868+ if (options & DDXMLNodeCompactEmptyElement)
869+ xmlSaveNoEmptyTags = 0;
870+ else
871+ xmlSaveNoEmptyTags = 1;
872+
873+ int format = 0;
874+ if (options & DDXMLNodePrettyPrint)
875+ {
876+ format = 1;
877+ xmlIndentTreeOutput = 1;
878+ }
879+
880+ xmlBufferPtr bufferPtr = xmlBufferCreate();
881+ if (IsXmlNsPtr(genericPtr))
882+ xmlNodeDump(bufferPtr, NULL, (xmlNodePtr)genericPtr, 0, format);
883+ else
884+ xmlNodeDump(bufferPtr, ((xmlStdPtr)genericPtr)->doc, (xmlNodePtr)genericPtr, 0, format);
885+
886+ if ([self kind] == DDXMLTextKind)
887+ {
888+ NSString *result = [NSString stringWithUTF8String:(const char *)bufferPtr->content];
889+
890+ xmlBufferFree(bufferPtr);
891+
892+ return result;
893+ }
894+ else
895+ {
896+ NSMutableString *resTmp = [NSMutableString stringWithUTF8String:(const char *)bufferPtr->content];
897+ CFStringTrimWhitespace((CFMutableStringRef)resTmp);
898+
899+ xmlBufferFree(bufferPtr);
900+
901+ return [[resTmp copy] autorelease];
902+ }
903+}
904+
905+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
906+#pragma mark XPath/XQuery
907+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
908+
909+- (NSArray *)nodesForXPath:(NSString *)xpath error:(NSError **)error
910+{
911+ xmlXPathContextPtr xpathCtx;
912+ xmlXPathObjectPtr xpathObj;
913+
914+ BOOL isTempDoc = NO;
915+ xmlDocPtr doc;
916+
917+ if (IsXmlDocPtr(genericPtr))
918+ {
919+ doc = (xmlDocPtr)genericPtr;
920+ }
921+ else if (IsXmlNodePtr(genericPtr))
922+ {
923+ doc = ((xmlNodePtr)genericPtr)->doc;
924+
925+ if(doc == NULL)
926+ {
927+ isTempDoc = YES;
928+
929+ doc = xmlNewDoc(NULL);
930+ xmlDocSetRootElement(doc, (xmlNodePtr)genericPtr);
931+ }
932+ }
933+ else
934+ {
935+ return nil;
936+ }
937+
938+ xpathCtx = xmlXPathNewContext(doc);
939+ xpathCtx->node = (xmlNodePtr)genericPtr;
940+
941+ xmlNodePtr rootNode = (doc)->children;
942+ if(rootNode != NULL)
943+ {
944+ xmlNsPtr ns = rootNode->nsDef;
945+ while(ns != NULL)
946+ {
947+ xmlXPathRegisterNs(xpathCtx, ns->prefix, ns->href);
948+
949+ ns = ns->next;
950+ }
951+ }
952+
953+ xpathObj = xmlXPathEvalExpression([xpath xmlChar], xpathCtx);
954+
955+ NSArray *result;
956+
957+ if(xpathObj == NULL)
958+ {
959+ if(error) *error = [[self class] lastError];
960+ result = nil;
961+ }
962+ else
963+ {
964+ if(error) *error = nil;
965+
966+ int count = xmlXPathNodeSetGetLength(xpathObj->nodesetval);
967+
968+ if(count == 0)
969+ {
970+ result = [NSArray array];
971+ }
972+ else
973+ {
974+ NSMutableArray *mResult = [NSMutableArray arrayWithCapacity:count];
975+
976+ int i;
977+ for (i = 0; i < count; i++)
978+ {
979+ xmlNodePtr node = xpathObj->nodesetval->nodeTab[i];
980+
981+ [mResult addObject:[DDXMLNode nodeWithUnknownPrimitive:(xmlKindPtr)node freeOnDealloc:NO]];
982+ }
983+
984+ result = mResult;
985+ }
986+ }
987+
988+ if(xpathObj) xmlXPathFreeObject(xpathObj);
989+ if(xpathCtx) xmlXPathFreeContext(xpathCtx);
990+
991+ if (isTempDoc)
992+ {
993+ xmlUnlinkNode((xmlNodePtr)genericPtr);
994+ xmlFreeDoc(doc);
995+
996+ // xmlUnlinkNode doesn't remove the doc ptr
997+ [[self class] recursiveStripDocPointersFromNode:(xmlNodePtr)genericPtr];
998+ }
999+
1000+ return result;
1001+}
1002+
1003+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1004+#pragma mark Private API
1005+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1006+
1007+// ---------- MEMORY MANAGEMENT ARCHITECTURE ----------
1008+//
1009+// KissXML is designed to be read-access thread-safe.
1010+// It is not write-access thread-safe as this would require significant overhead.
1011+//
1012+// What exactly does read-access thread-safe mean?
1013+// It means that multiple threads can safely read from the same xml structure,
1014+// so long as none of them attempt to alter the xml structure (add/remove nodes, change attributes, etc).
1015+//
1016+// This read-access thread-safety includes parsed xml structures as well as xml structures created by you.
1017+// Let's walk through a few examples to get a deeper understanding.
1018+//
1019+//
1020+//
1021+// Example #1 - Parallel processing of children
1022+//
1023+// DDXMLElement *root = [[DDXMLElement alloc] initWithXMLString:str error:nil];
1024+// NSArray *children = [root children];
1025+//
1026+// dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
1027+// dispatch_apply([children count], q, ^(size_t i) {
1028+// DDXMLElement *child = [children objectAtIndex:i];
1029+// <process child>
1030+// });
1031+//
1032+//
1033+//
1034+// Example #2 - Safe vs Unsafe sub-element processing
1035+//
1036+// DDXMLElement *root = [[DDXMLElement alloc] initWithXMLString:str error:nil];
1037+// DDXMLElement *child = [root elementForName:@"starbucks"];
1038+//
1039+// dispatch_async(queue, ^{
1040+// <process child>
1041+// });
1042+//
1043+// [root release]; <-------------- NOT safe!
1044+//
1045+// But why is it not safe?
1046+// Does it have something to do with the child?
1047+// Do I need to retain the child?
1048+// Doesn't the child get retained automatically by dispatch_async?
1049+//
1050+// Yes, the child does get retainied automatically by dispatch_async, but that's not the problem.
1051+// XML represents a heirarchy of nodes. For example:
1052+//
1053+// <root>
1054+// <starbucks>
1055+// <coffee/>
1056+// </starbucks>
1057+// </root>
1058+//
1059+// Each element within the heirarchy has references/pointers to its parent, children, siblings, etc.
1060+// This is necessary to support the traversal strategies one requires to work with XML.
1061+// This also means its not thread-safe to deallocate the root node of an element if
1062+// you are still using/accessing a child node.
1063+// So let's rewrite example 2 in a thread-safe manner this time.
1064+//
1065+// DDXMLElement *root = [[DDXMLElement alloc] initWithXMLString:str error:nil];
1066+// DDXMLElement *child = [root elementForName:@"starbucks"];
1067+//
1068+// [child detach]; <-------------- Detached from root, and can safely be used even if we now dealloc root.
1069+//
1070+// dispatch_async(queue, ^{
1071+// <process child>
1072+// });
1073+//
1074+// [root release]; <-------------- Thread-safe thanks to the detach above.
1075+//
1076+//
1077+//
1078+// Example #3 - Building up an element
1079+//
1080+// DDXMLElement *coffee = [[DDXMLElement alloc] initWithName:@"coffee"];
1081+// DDXMLElement *starbucks = [[DDXMLElement alloc] initWithName:@"starbucks"];
1082+// DDXMLElement *root = [[DDXMLElement alloc] initWithName:@"root"];
1083+//
1084+// At this point we have 3 root nodes (root, starbucks, coffee)
1085+//
1086+// [starbucks addChild:coffee];
1087+//
1088+// At this point we have 2 root nodes (root, starbucks).
1089+// The coffee node is now a child of starbucks, so it is no-longer a "root" node since
1090+// it has a parent within the xml tree heirarchy.
1091+//
1092+// [coffee addChild:starbucks];
1093+//
1094+// At this point we have only 1 root node (root).
1095+// Again, the others are no-longer "root" nodes since they have a parent within the xml tree heirarchy.
1096+//
1097+// [coffee release]; coffee = nil;
1098+//
1099+// If you have a reference to a child node, you can safely release that reference.
1100+// Since coffee is embedded in the tree heirarchy, the coffee node doesn't disappear.
1101+//
1102+// DDXMLElement *coffee2 = [starbucks elementForName:@"coffee"];
1103+//
1104+// So the above will return a new reference to the coffee node.
1105+//
1106+// [root release]; root = nil;
1107+//
1108+// Now, we have just released the root node.
1109+// This means that it is no longer safe to use starbucks or coffee2.
1110+//
1111+// [starbucks release]; starbucks = nil;
1112+//
1113+// Yes, this is safe. Just don't do anything else with starbucks besides release it.
1114+
1115+/**
1116+ * Returns whether or not the node has a parent.
1117+ * Use this method instead of parent when you only need to ensure parent is nil.
1118+ * This prevents the unnecessary creation of a parent node wrapper.
1119+**/
1120+- (BOOL)hasParent
1121+{
1122+ // Note: DDXMLNamespaceNode overrides this method
1123+
1124+ xmlStdPtr node = (xmlStdPtr)genericPtr;
1125+
1126+ return (node->parent != NULL);
1127+}
1128+
1129++ (void)stripDocPointersFromAttr:(xmlAttrPtr)attr
1130+{
1131+ xmlNodePtr child = attr->children;
1132+ while (child != NULL)
1133+ {
1134+ child->doc = NULL;
1135+ child = child->next;
1136+ }
1137+
1138+ attr->doc = NULL;
1139+}
1140+
1141++ (void)recursiveStripDocPointersFromNode:(xmlNodePtr)node
1142+{
1143+ xmlAttrPtr attr = node->properties;
1144+ while (attr != NULL)
1145+ {
1146+ [self stripDocPointersFromAttr:attr];
1147+ attr = attr->next;
1148+ }
1149+
1150+ xmlNodePtr child = node->children;
1151+ while (child != NULL)
1152+ {
1153+ [self recursiveStripDocPointersFromNode:child];
1154+ child = child->next;
1155+ }
1156+
1157+ node->doc = NULL;
1158+}
1159+
1160+/**
1161+ * Detaches the given attribute from the given node.
1162+ * The attribute's surrounding prev/next pointers are properly updated to remove the attribute from the attr list.
1163+ * Then, if flag is YES, the attribute's parent, prev, next and doc pointers are destroyed.
1164+**/
1165++ (void)detachAttribute:(xmlAttrPtr)attr fromNode:(xmlNodePtr)node andNullifyPointers:(BOOL)flag
1166+{
1167+ // Update the surrounding prev/next pointers
1168+ if (attr->prev == NULL)
1169+ {
1170+ if (attr->next == NULL)
1171+ {
1172+ node->properties = NULL;
1173+ }
1174+ else
1175+ {
1176+ node->properties = attr->next;
1177+ attr->next->prev = NULL;
1178+ }
1179+ }
1180+ else
1181+ {
1182+ if (attr->next == NULL)
1183+ {
1184+ attr->prev->next = NULL;
1185+ }
1186+ else
1187+ {
1188+ attr->prev->next = attr->next;
1189+ attr->next->prev = attr->prev;
1190+ }
1191+ }
1192+
1193+ if (flag)
1194+ {
1195+ // Nullify pointers
1196+ attr->parent = NULL;
1197+ attr->prev = NULL;
1198+ attr->next = NULL;
1199+ if(attr->doc != NULL) [self stripDocPointersFromAttr:attr];
1200+ }
1201+}
1202+
1203+/**
1204+ * Detaches the given attribute from the given node.
1205+ * The attribute's surrounding prev/next pointers are properly updated to remove the attribute from the attr list.
1206+ * Then the attribute's parent, prev, next and doc pointers are destroyed.
1207+**/
1208++ (void)detachAttribute:(xmlAttrPtr)attr fromNode:(xmlNodePtr)node
1209+{
1210+ [self detachAttribute:attr fromNode:node andNullifyPointers:YES];
1211+}
1212+
1213+/**
1214+ * Removes and free's the given attribute from the given node.
1215+ * The attribute's surrounding prev/next pointers are properly updated to remove the attribute from the attr list.
1216+**/
1217++ (void)removeAttribute:(xmlAttrPtr)attr fromNode:(xmlNodePtr)node
1218+{
1219+ // We perform a bit of optimization here.
1220+ // No need to bother nullifying pointers since we're about to free the node anyway.
1221+ [self detachAttribute:attr fromNode:node andNullifyPointers:NO];
1222+
1223+ xmlFreeProp(attr);
1224+}
1225+
1226+/**
1227+ * Removes and frees all attributes from the given node.
1228+ * Upon return, the given node's properties pointer is NULL.
1229+**/
1230++ (void)removeAllAttributesFromNode:(xmlNodePtr)node
1231+{
1232+ xmlAttrPtr attr = node->properties;
1233+
1234+ while (attr != NULL)
1235+ {
1236+ xmlAttrPtr nextAttr = attr->next;
1237+
1238+ xmlFreeProp(attr);
1239+
1240+ attr = nextAttr;
1241+ }
1242+
1243+ node->properties = NULL;
1244+}
1245+
1246+/**
1247+ * Detaches the given namespace from the given node.
1248+ * The namespace's surrounding next pointers are properly updated to remove the namespace from the node's nsDef list.
1249+ * Then the namespace's parent and next pointers are destroyed.
1250+**/
1251++ (void)detachNamespace:(xmlNsPtr)ns fromNode:(xmlNodePtr)node
1252+{
1253+ // Namespace nodes have no previous pointer, so we have to search for the node
1254+
1255+ xmlNsPtr previousNs = NULL;
1256+ xmlNsPtr currentNs = node->nsDef;
1257+
1258+ while (currentNs != NULL)
1259+ {
1260+ if (currentNs == ns)
1261+ {
1262+ if (previousNs == NULL)
1263+ node->nsDef = currentNs->next;
1264+ else
1265+ previousNs->next = currentNs->next;
1266+
1267+ break;
1268+ }
1269+
1270+ previousNs = currentNs;
1271+ currentNs = currentNs->next;
1272+ }
1273+
1274+ if (node->ns == ns)
1275+ {
1276+ node->ns = NULL;
1277+ }
1278+
1279+ // Nullify pointers
1280+ //ns->_private = NULL; Todo
1281+ ns->next = NULL;
1282+}
1283+
1284+/**
1285+ * Removes the given namespace from the given node.
1286+ * The namespace's surrounding next pointers are properly updated to remove the namespace from the nsDef list.
1287+ * Then the namespace is freed if it's no longer being referenced.
1288+ * Otherwise, it's nsParent and next pointers are destroyed.
1289+**/
1290++ (void)removeNamespace:(xmlNsPtr)ns fromNode:(xmlNodePtr)node
1291+{
1292+ [self detachNamespace:ns fromNode:node];
1293+
1294+ xmlFreeNs(ns);
1295+}
1296+
1297+/**
1298+ * Removes all namespaces from the given node.
1299+ * All namespaces are either freed, or their nsParent and next pointers are properly destroyed.
1300+ * Upon return, the given node's nsDef pointer is NULL.
1301+**/
1302++ (void)removeAllNamespacesFromNode:(xmlNodePtr)node
1303+{
1304+ xmlNsPtr ns = node->nsDef;
1305+
1306+ while (ns != NULL)
1307+ {
1308+ xmlNsPtr nextNs = ns->next;
1309+
1310+ xmlFreeNs(ns);
1311+
1312+ ns = nextNs;
1313+ }
1314+
1315+ node->nsDef = NULL;
1316+ node->ns = NULL;
1317+}
1318+
1319+/**
1320+ * Detaches the given child from the given node.
1321+ * The child's surrounding prev/next pointers are properly updated to remove the child from the node's children list.
1322+ * Then, if flag is YES, the child's parent, prev, next and doc pointers are destroyed.
1323+**/
1324++ (void)detachChild:(xmlNodePtr)child fromNode:(xmlNodePtr)node andNullifyPointers:(BOOL)flag
1325+{
1326+ // Update the surrounding prev/next pointers
1327+ if (child->prev == NULL)
1328+ {
1329+ if (child->next == NULL)
1330+ {
1331+ node->children = NULL;
1332+ node->last = NULL;
1333+ }
1334+ else
1335+ {
1336+ node->children = child->next;
1337+ child->next->prev = NULL;
1338+ }
1339+ }
1340+ else
1341+ {
1342+ if (child->next == NULL)
1343+ {
1344+ node->last = child->prev;
1345+ child->prev->next = NULL;
1346+ }
1347+ else
1348+ {
1349+ child->prev->next = child->next;
1350+ child->next->prev = child->prev;
1351+ }
1352+ }
1353+
1354+ if (flag)
1355+ {
1356+ // Nullify pointers
1357+ child->parent = NULL;
1358+ child->prev = NULL;
1359+ child->next = NULL;
1360+ if(child->doc != NULL) [self recursiveStripDocPointersFromNode:child];
1361+ }
1362+}
1363+
1364+/**
1365+ * Detaches the given child from the given node.
1366+ * The child's surrounding prev/next pointers are properly updated to remove the child from the node's children list.
1367+ * Then the child's parent, prev, next and doc pointers are destroyed.
1368+**/
1369++ (void)detachChild:(xmlNodePtr)child fromNode:(xmlNodePtr)node
1370+{
1371+ [self detachChild:child fromNode:node andNullifyPointers:YES];
1372+}
1373+
1374+/**
1375+ * Removes the given child from the given node.
1376+ * The child's surrounding prev/next pointers are properly updated to remove the child from the node's children list.
1377+ * Then the child is recursively freed if it's no longer being referenced.
1378+ * Otherwise, it's parent, prev, next and doc pointers are destroyed.
1379+ *
1380+ * During the recursive free, subnodes still being referenced are properly handled.
1381+**/
1382++ (void)removeChild:(xmlNodePtr)child fromNode:(xmlNodePtr)node
1383+{
1384+ // We perform a bit of optimization here.
1385+ // No need to bother nullifying pointers since we're about to free the node anyway.
1386+ [self detachChild:child fromNode:node andNullifyPointers:NO];
1387+
1388+ xmlFreeNode(child);
1389+}
1390+
1391+/**
1392+ * Removes all children from the given node.
1393+ * All children are either recursively freed, or their parent, prev, next and doc pointers are properly destroyed.
1394+ * Upon return, the given node's children pointer is NULL.
1395+ *
1396+ * During the recursive free, subnodes still being referenced are properly handled.
1397+**/
1398++ (void)removeAllChildrenFromNode:(xmlNodePtr)node
1399+{
1400+ xmlNodePtr child = node->children;
1401+
1402+ while (child != NULL)
1403+ {
1404+ xmlNodePtr nextChild = child->next;
1405+
1406+ xmlFreeNode(child);
1407+
1408+ child = nextChild;
1409+ }
1410+
1411+ node->children = NULL;
1412+ node->last = NULL;
1413+}
1414+
1415+/**
1416+ * Returns the last error encountered by libxml.
1417+ * Errors are caught in the MyErrorHandler method within DDXMLDocument.
1418+**/
1419++ (NSError *)lastError
1420+{
1421+ NSValue *lastErrorValue = [[[NSThread currentThread] threadDictionary] objectForKey:DDLastErrorKey];
1422+ if(lastErrorValue)
1423+ {
1424+ xmlError lastError;
1425+ [lastErrorValue getValue:&lastError];
1426+
1427+ int errCode = lastError.code;
1428+ NSString *errMsg = [[NSString stringWithFormat:@"%s", lastError.message] stringByTrimming];
1429+
1430+ NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
1431+
1432+ return [NSError errorWithDomain:@"DDXMLErrorDomain" code:errCode userInfo:info];
1433+ }
1434+ else
1435+ {
1436+ return nil;
1437+ }
1438+}
1439+
1440+static void MyErrorHandler(void * userData, xmlErrorPtr error)
1441+{
1442+ // This method is called by libxml when an error occurs.
1443+ // We register for this error in the initialize method below.
1444+
1445+ // Extract error message and store in the current thread's dictionary.
1446+ // This ensure's thread safey, and easy access for all other DDXML classes.
1447+
1448+ if (error == NULL)
1449+ {
1450+ [[[NSThread currentThread] threadDictionary] removeObjectForKey:DDLastErrorKey];
1451+ }
1452+ else
1453+ {
1454+ NSValue *errorValue = [NSValue valueWithBytes:error objCType:@encode(xmlError)];
1455+
1456+ [[[NSThread currentThread] threadDictionary] setObject:errorValue forKey:DDLastErrorKey];
1457+ }
1458+}
1459+
1460+@end
1461+
1462+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1463+#pragma mark -
1464+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1465+
1466+@implementation DDXMLNamespaceNode
1467+
1468+/**
1469+ * Returns a DDXML wrapper object for the given primitive node.
1470+ * The given node MUST be non-NULL and of the proper type.
1471+**/
1472++ (id)nodeWithNsPrimitive:(xmlNsPtr)ns nsParent:(xmlNodePtr)parent freeOnDealloc:(BOOL)flag
1473+{
1474+ return [[[DDXMLNamespaceNode alloc] initWithNsPrimitive:ns nsParent:parent freeOnDealloc:flag] autorelease];
1475+}
1476+
1477+/**
1478+ * Returns a DDXML wrapper object for the given primitive node.
1479+ * The given node MUST be non-NULL and of the proper type.
1480+**/
1481+- (id)initWithNsPrimitive:(xmlNsPtr)ns nsParent:(xmlNodePtr)parent freeOnDealloc:(BOOL)flag
1482+{
1483+ if ((self = [super init]))
1484+ {
1485+ genericPtr = (xmlKindPtr)ns;
1486+ nsParentPtr = parent;
1487+ freeOnDealloc = flag;
1488+ }
1489+ return self;
1490+}
1491+
1492++ (id)nodeWithPrimitive:(xmlKindPtr)kindPtr freeOnDealloc:(BOOL)flag
1493+{
1494+ // Promote initializers which use proper parameter types to enable compiler to catch more mistakes.
1495+ NSAssert(NO, @"Use nodeWithNsPrimitive:nsParent:freeOnDealloc:");
1496+
1497+ return nil;
1498+}
1499+
1500+- (id)initWithPrimitive:(xmlKindPtr)kindPtr freeOnDealloc:(BOOL)flag
1501+{
1502+ // Promote initializers which use proper parameter types to enable compiler to catch more mistakes.
1503+ NSAssert(NO, @"Use initWithNsPrimitive:nsParent:freeOnDealloc:");
1504+
1505+ [self release];
1506+ return nil;
1507+}
1508+
1509+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1510+#pragma mark Properties
1511+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1512+
1513+- (void)setName:(NSString *)name
1514+{
1515+ xmlNsPtr ns = (xmlNsPtr)genericPtr;
1516+
1517+ xmlFree((xmlChar *)ns->prefix);
1518+ ns->prefix = xmlStrdup([name xmlChar]);
1519+}
1520+
1521+- (NSString *)name
1522+{
1523+ xmlNsPtr ns = (xmlNsPtr)genericPtr;
1524+ if (ns->prefix != NULL)
1525+ return [NSString stringWithUTF8String:((const char*)ns->prefix)];
1526+ else
1527+ return @"";
1528+}
1529+
1530+- (void)setStringValue:(NSString *)string
1531+{
1532+ xmlNsPtr ns = (xmlNsPtr)genericPtr;
1533+
1534+ xmlFree((xmlChar *)ns->href);
1535+ ns->href = xmlEncodeSpecialChars(NULL, [string xmlChar]);
1536+}
1537+
1538+- (NSString *)stringValue
1539+{
1540+ return [NSString stringWithUTF8String:((const char *)((xmlNsPtr)genericPtr)->href)];
1541+}
1542+
1543+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1544+#pragma mark Tree Navigation
1545+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1546+
1547+- (NSUInteger)index
1548+{
1549+ xmlNsPtr ns = (xmlNsPtr)genericPtr;
1550+
1551+ // The xmlNsPtr has no prev pointer, so we have to search from the parent
1552+
1553+ if (nsParentPtr == NULL)
1554+ {
1555+ return 0;
1556+ }
1557+
1558+ NSUInteger result = 0;
1559+
1560+ xmlNsPtr currentNs = nsParentPtr->nsDef;
1561+ while (currentNs != NULL)
1562+ {
1563+ if (currentNs == ns)
1564+ {
1565+ return result;
1566+ }
1567+ result++;
1568+ currentNs = currentNs->next;
1569+ }
1570+
1571+ return 0; // Yes 0, not result, because ns wasn't found in list
1572+}
1573+
1574+- (NSUInteger)level
1575+{
1576+ NSUInteger result = 0;
1577+
1578+ xmlNodePtr currentNode = nsParentPtr;
1579+ while (currentNode != NULL)
1580+ {
1581+ result++;
1582+ currentNode = currentNode->parent;
1583+ }
1584+
1585+ return result;
1586+}
1587+
1588+- (DDXMLDocument *)rootDocument
1589+{
1590+ xmlStdPtr node = (xmlStdPtr)nsParentPtr;
1591+
1592+ if (node == NULL || node->doc == NULL)
1593+ return nil;
1594+ else
1595+ return [DDXMLDocument nodeWithDocPrimitive:node->doc freeOnDealloc:NO];
1596+}
1597+
1598+- (DDXMLNode *)parent
1599+{
1600+ if (nsParentPtr == NULL)
1601+ return nil;
1602+ else
1603+ return [DDXMLNode nodeWithUnknownPrimitive:(xmlKindPtr)nsParentPtr freeOnDealloc:NO];
1604+}
1605+
1606+- (NSUInteger)childCount
1607+{
1608+ return 0;
1609+}
1610+
1611+- (NSArray *)children
1612+{
1613+ return nil;
1614+}
1615+
1616+- (DDXMLNode *)childAtIndex:(NSUInteger)index
1617+{
1618+ return nil;
1619+}
1620+
1621+- (DDXMLNode *)previousSibling
1622+{
1623+ return nil;
1624+}
1625+
1626+- (DDXMLNode *)nextSibling
1627+{
1628+ return nil;
1629+}
1630+
1631+- (DDXMLNode *)previousNode
1632+{
1633+ return nil;
1634+}
1635+
1636+- (DDXMLNode *)nextNode
1637+{
1638+ return nil;
1639+}
1640+
1641+- (void)detach
1642+{
1643+ if (nsParentPtr != NULL)
1644+ {
1645+ [DDXMLNode detachNamespace:(xmlNsPtr)genericPtr fromNode:nsParentPtr];
1646+
1647+ freeOnDealloc = YES;
1648+ nsParentPtr = NULL;
1649+ }
1650+}
1651+
1652+- (xmlStdPtr)XPathPreProcess:(NSMutableString *)result
1653+{
1654+ xmlStdPtr parent = (xmlStdPtr)nsParentPtr;
1655+
1656+ if (parent == NULL)
1657+ [result appendFormat:@"namespace::%@", [self name]];
1658+ else
1659+ [result appendFormat:@"/namespace::%@", [self name]];
1660+
1661+ return parent;
1662+}
1663+
1664+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1665+#pragma mark QNames
1666+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1667+
1668+- (NSString *)localName
1669+{
1670+ // Strangely enough, the localName of a namespace is the prefix, and the prefix is an empty string
1671+ xmlNsPtr ns = (xmlNsPtr)genericPtr;
1672+ if (ns->prefix != NULL)
1673+ return [NSString stringWithUTF8String:((const char *)ns->prefix)];
1674+ else
1675+ return @"";
1676+}
1677+
1678+- (NSString *)prefix
1679+{
1680+ // Strangely enough, the localName of a namespace is the prefix, and the prefix is an empty string
1681+ return @"";
1682+}
1683+
1684+- (void)setURI:(NSString *)URI
1685+{
1686+ // Do nothing
1687+}
1688+
1689+- (NSString *)URI
1690+{
1691+ return nil;
1692+}
1693+
1694+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1695+#pragma mark Private API
1696+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1697+
1698+- (BOOL)hasParent
1699+{
1700+ return (nsParentPtr != NULL);
1701+}
1702+
1703+- (xmlNodePtr)nsParentPtr
1704+{
1705+ return nsParentPtr;
1706+}
1707+
1708+- (void)setNsParentPtr:(xmlNodePtr)parentPtr
1709+{
1710+ nsParentPtr = parentPtr;
1711+}
1712+
1713+@end
1714+
1715+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1716+#pragma mark -
1717+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1718+
1719+@implementation DDXMLAttributeNode
1720+
1721++ (id)nodeWithAttrPrimitive:(xmlAttrPtr)attr freeOnDealloc:(BOOL)flag
1722+{
1723+ return [[[DDXMLAttributeNode alloc] initWithAttrPrimitive:attr freeOnDealloc:flag] autorelease];
1724+}
1725+
1726+- (id)initWithAttrPrimitive:(xmlAttrPtr)attr freeOnDealloc:(BOOL)flag
1727+{
1728+ self = [super initWithPrimitive:(xmlKindPtr)attr freeOnDealloc:flag];
1729+ return self;
1730+}
1731+
1732++ (id)nodeWithPrimitive:(xmlKindPtr)kindPtr freeOnDealloc:(BOOL)flag
1733+{
1734+ // Promote initializers which use proper parameter types to enable compiler to catch more mistakes.
1735+ NSAssert(NO, @"Use nodeWithAttrPrimitive:nsParent:freeOnDealloc:");
1736+
1737+ return nil;
1738+}
1739+
1740+- (id)initWithPrimitive:(xmlKindPtr)kindPtr freeOnDealloc:(BOOL)flag
1741+{
1742+ // Promote initializers which use proper parameter types to enable compiler to catch more mistakes.
1743+ NSAssert(NO, @"Use initWithAttrPrimitive:nsParent:freeOnDealloc:");
1744+
1745+ [self release];
1746+ return nil;
1747+}
1748+
1749+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1750+#pragma mark Properties
1751+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1752+
1753+- (void)setStringValue:(NSString *)string
1754+{
1755+ xmlAttrPtr attr = (xmlAttrPtr)genericPtr;
1756+
1757+ if (attr->children != NULL)
1758+ {
1759+ xmlChar *escapedString = xmlEncodeSpecialChars(attr->doc, [string xmlChar]);
1760+ xmlNodeSetContent((xmlNodePtr)attr, escapedString);
1761+ xmlFree(escapedString);
1762+ }
1763+ else
1764+ {
1765+ xmlNodePtr text = xmlNewText([string xmlChar]);
1766+ attr->children = text;
1767+ }
1768+}
1769+
1770+- (NSString *)stringValue
1771+{
1772+ xmlAttrPtr attr = (xmlAttrPtr)genericPtr;
1773+
1774+ if (attr->children != NULL)
1775+ {
1776+ return [NSString stringWithUTF8String:(const char *)attr->children->content];
1777+ }
1778+
1779+ return nil;
1780+}
1781+
1782+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1783+#pragma mark Tree Navigation
1784+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1785+
1786+- (DDXMLNode *)previousNode
1787+{
1788+ return nil;
1789+}
1790+
1791+- (DDXMLNode *)nextNode
1792+{
1793+ return nil;
1794+}
1795+
1796+- (void)detach
1797+{
1798+ xmlAttrPtr attr = (xmlAttrPtr)genericPtr;
1799+
1800+ if (attr->parent != NULL)
1801+ {
1802+ [[self class] detachAttribute:attr fromNode:attr->parent];
1803+ freeOnDealloc = YES;
1804+ }
1805+}
1806+
1807+- (xmlStdPtr)XPathPreProcess:(NSMutableString *)result
1808+{
1809+ // Note: DDXMLNamespaceNode overrides this method
1810+ // Note: DDXMLAttributeNode overrides this method
1811+
1812+ xmlAttrPtr attr = (xmlAttrPtr)genericPtr;
1813+ xmlStdPtr parent = (xmlStdPtr)attr->parent;
1814+
1815+ if (parent == NULL)
1816+ [result appendFormat:@"@%@", [self name]];
1817+ else
1818+ [result appendFormat:@"/@%@", [self name]];
1819+
1820+ return parent;
1821+}
1822+
1823+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1824+#pragma mark QNames
1825+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1826+
1827+- (void)setURI:(NSString *)URI
1828+{
1829+ xmlAttrPtr attr = (xmlAttrPtr)genericPtr;
1830+ if (attr->ns != NULL)
1831+ {
1832+ // An attribute can only have a single namespace attached to it.
1833+ // In addition, this namespace can only be accessed via the URI method.
1834+ // There is no way, within the API, to get a DDXMLNode wrapper for the attribute's namespace.
1835+ xmlFreeNs(attr->ns);
1836+ attr->ns = NULL;
1837+ }
1838+
1839+ if (URI)
1840+ {
1841+ // Create a new xmlNsPtr, and make ns point to it
1842+ xmlNsPtr ns = xmlNewNs(NULL, [URI xmlChar], NULL);
1843+ attr->ns = ns;
1844+ }
1845+}
1846+
1847+- (NSString *)URI
1848+{
1849+ xmlAttrPtr attr = (xmlAttrPtr)genericPtr;
1850+ if (attr->ns != NULL)
1851+ {
1852+ return [NSString stringWithUTF8String:((const char *)attr->ns->href)];
1853+ }
1854+
1855+ return nil;
1856+}
1857+
1858+@end
--- trunk/0.2.X/KissXML/Private/DDXMLPrivate.h (nonexistent)
+++ trunk/0.2.X/KissXML/Private/DDXMLPrivate.h (revision 274)
@@ -0,0 +1,183 @@
1+#import "DDXML.h"
2+
3+
4+// We can't rely solely on NSAssert, because many developers disable them for release builds.
5+// Our API contract requires us to keep these assertions intact.
6+#define DDXMLAssert(condition, desc, ...) \
7+ do{ \
8+ if(!(condition)) \
9+ { \
10+ [[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd \
11+ object:self \
12+ file:[NSString stringWithUTF8String:__FILE__] \
13+ lineNumber:__LINE__ \
14+ description:(desc), ##__VA_ARGS__]; \
15+ } \
16+ }while(NO)
17+
18+#define DDLastErrorKey @"DDXML:LastError"
19+
20+/**
21+ * DDXMLNode can represent several underlying types, such as xmlNodePtr, xmlDocPtr, xmlAttrPtr, xmlNsPtr, etc.
22+ * All of these are pointers to structures, and all of those structures start with a pointer, and a type.
23+ * The xmlKind struct is used as a generic structure, and a stepping stone.
24+ * We use it to check the type of a structure, and then perform the appropriate cast.
25+ *
26+ * For example:
27+ * if(genericPtr->type == XML_ATTRIBUTE_NODE)
28+ * {
29+ * xmlAttrPtr attr = (xmlAttrPtr)genericPtr;
30+ * // Do something with attr
31+ * }
32+**/
33+struct _xmlKind {
34+ void * ignore;
35+ xmlElementType type;
36+};
37+typedef struct _xmlKind *xmlKindPtr;
38+
39+/**
40+ * Most xml types all start with this standard structure. In fact, all do except the xmlNsPtr.
41+ * We will occasionally take advantage of this to simplify code when the code wouldn't vary from type to type.
42+ * Obviously, you cannnot cast a xmlNsPtr to a xmlStdPtr.
43+**/
44+struct _xmlStd {
45+ void * _private;
46+ xmlElementType type;
47+ const xmlChar *name;
48+ struct _xmlNode *children;
49+ struct _xmlNode *last;
50+ struct _xmlNode *parent;
51+ struct _xmlStd *next;
52+ struct _xmlStd *prev;
53+ struct _xmlDoc *doc;
54+};
55+typedef struct _xmlStd *xmlStdPtr;
56+
57+
58+NS_INLINE BOOL IsXmlAttrPtr(void *kindPtr)
59+{
60+ return ((xmlKindPtr)kindPtr)->type == XML_ATTRIBUTE_NODE;
61+}
62+
63+NS_INLINE BOOL IsXmlNodePtr(void *kindPtr)
64+{
65+ switch (((xmlKindPtr)kindPtr)->type)
66+ {
67+ case XML_ELEMENT_NODE :
68+ case XML_PI_NODE :
69+ case XML_COMMENT_NODE :
70+ case XML_TEXT_NODE :
71+ case XML_CDATA_SECTION_NODE : return YES;
72+ default : return NO;
73+ }
74+}
75+
76+NS_INLINE BOOL IsXmlDocPtr(void *kindPtr)
77+{
78+ return ((xmlKindPtr)kindPtr)->type == XML_DOCUMENT_NODE;
79+}
80+
81+NS_INLINE BOOL IsXmlDtdPtr(void *kindPtr)
82+{
83+ return ((xmlKindPtr)kindPtr)->type == XML_DTD_NODE;
84+}
85+
86+NS_INLINE BOOL IsXmlNsPtr(void *kindPtr)
87+{
88+ return ((xmlKindPtr)kindPtr)->type == XML_NAMESPACE_DECL;
89+}
90+
91+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
92+#pragma mark -
93+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
94+
95+@interface DDXMLNamespaceNode : DDXMLNode
96+{
97+ // The xmlNsPtr type doesn't store a reference to it's parent.
98+ // This is here to fix the problem, and make this class more compatible with the NSXML classes.
99+ xmlNodePtr nsParentPtr;
100+}
101+
102++ (id)nodeWithNsPrimitive:(xmlNsPtr)ns nsParent:(xmlNodePtr)parent freeOnDealloc:(BOOL)flag;
103+- (id)initWithNsPrimitive:(xmlNsPtr)ns nsParent:(xmlNodePtr)parent freeOnDealloc:(BOOL)flag;
104+
105+- (xmlNodePtr)nsParentPtr;
106+- (void)setNsParentPtr:(xmlNodePtr)parentPtr;
107+
108+// Overrides several methods in DDXMLNode
109+
110+@end
111+
112+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
113+#pragma mark -
114+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
115+
116+@interface DDXMLAttributeNode : DDXMLNode
117+
118++ (id)nodeWithAttrPrimitive:(xmlAttrPtr)attr freeOnDealloc:(BOOL)flag;
119+- (id)initWithAttrPrimitive:(xmlAttrPtr)attr freeOnDealloc:(BOOL)flag;
120+
121+// Overrides several methods in DDXMLNode
122+
123+@end
124+
125+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
126+#pragma mark -
127+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
128+
129+@interface DDXMLNode (PrivateAPI)
130+
131++ (id)nodeWithUnknownPrimitive:(xmlKindPtr)kindPtr freeOnDealloc:(BOOL)flag;
132+
133++ (id)nodeWithPrimitive:(xmlKindPtr)kindPtr freeOnDealloc:(BOOL)flag;
134+- (id)initWithPrimitive:(xmlKindPtr)kindPtr freeOnDealloc:(BOOL)flag;
135+
136+- (BOOL)hasParent;
137+
138++ (void)recursiveStripDocPointersFromNode:(xmlNodePtr)node;
139+
140++ (void)detachAttribute:(xmlAttrPtr)attr fromNode:(xmlNodePtr)node;
141++ (void)removeAttribute:(xmlAttrPtr)attr fromNode:(xmlNodePtr)node;
142++ (void)removeAllAttributesFromNode:(xmlNodePtr)node;
143+
144++ (void)detachNamespace:(xmlNsPtr)ns fromNode:(xmlNodePtr)node;
145++ (void)removeNamespace:(xmlNsPtr)ns fromNode:(xmlNodePtr)node;
146++ (void)removeAllNamespacesFromNode:(xmlNodePtr)node;
147+
148++ (void)detachChild:(xmlNodePtr)child fromNode:(xmlNodePtr)node;
149++ (void)removeChild:(xmlNodePtr)child fromNode:(xmlNodePtr)node;
150++ (void)removeAllChildrenFromNode:(xmlNodePtr)node;
151+
152+- (void)nodeFree;
153+
154++ (NSError *)lastError;
155+
156+@end
157+
158+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
159+#pragma mark -
160+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
161+
162+@interface DDXMLElement (PrivateAPI)
163+
164++ (id)nodeWithElementPrimitive:(xmlNodePtr)node freeOnDealloc:(BOOL)flag;
165+- (id)initWithElementPrimitive:(xmlNodePtr)node freeOnDealloc:(BOOL)flag;
166+
167+- (NSArray *)elementsForName:(NSString *)name uri:(NSString *)URI;
168+
169++ (DDXMLNode *)resolveNamespaceForPrefix:(NSString *)prefix atNode:(xmlNodePtr)nodePtr;
170++ (NSString *)resolvePrefixForURI:(NSString *)uri atNode:(xmlNodePtr)nodePtr;
171+
172+@end
173+
174+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
175+#pragma mark -
176+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
177+
178+@interface DDXMLDocument (PrivateAPI)
179+
180++ (id)nodeWithDocPrimitive:(xmlDocPtr)doc freeOnDealloc:(BOOL)flag;
181+- (id)initWithDocPrimitive:(xmlDocPtr)doc freeOnDealloc:(BOOL)flag;
182+
183+@end
--- trunk/0.2.X/KissXML/DDXMLDocument.h (nonexistent)
+++ trunk/0.2.X/KissXML/DDXMLDocument.h (revision 274)
@@ -0,0 +1,67 @@
1+#import <Foundation/Foundation.h>
2+#import "DDXMLElement.h"
3+#import "DDXMLNode.h"
4+
5+
6+enum {
7+ DDXMLDocumentXMLKind = 0,
8+ DDXMLDocumentXHTMLKind,
9+ DDXMLDocumentHTMLKind,
10+ DDXMLDocumentTextKind
11+};
12+typedef NSUInteger DDXMLDocumentContentKind;
13+
14+@interface DDXMLDocument : DDXMLNode
15+{
16+}
17+
18+- (id)initWithXMLString:(NSString *)string options:(NSUInteger)mask error:(NSError **)error;
19+//- (id)initWithContentsOfURL:(NSURL *)url options:(NSUInteger)mask error:(NSError **)error;
20+- (id)initWithData:(NSData *)data options:(NSUInteger)mask error:(NSError **)error;
21+//- (id)initWithRootElement:(DDXMLElement *)element;
22+
23+//+ (Class)replacementClassForClass:(Class)cls;
24+
25+//- (void)setCharacterEncoding:(NSString *)encoding; //primitive
26+//- (NSString *)characterEncoding; //primitive
27+
28+//- (void)setVersion:(NSString *)version;
29+//- (NSString *)version;
30+
31+//- (void)setStandalone:(BOOL)standalone;
32+//- (BOOL)isStandalone;
33+
34+//- (void)setDocumentContentKind:(DDXMLDocumentContentKind)kind;
35+//- (DDXMLDocumentContentKind)documentContentKind;
36+
37+//- (void)setMIMEType:(NSString *)MIMEType;
38+//- (NSString *)MIMEType;
39+
40+//- (void)setDTD:(DDXMLDTD *)documentTypeDeclaration;
41+//- (DDXMLDTD *)DTD;
42+
43+//- (void)setRootElement:(DDXMLNode *)root;
44+- (DDXMLElement *)rootElement;
45+
46+//- (void)insertChild:(DDXMLNode *)child atIndex:(NSUInteger)index;
47+
48+//- (void)insertChildren:(NSArray *)children atIndex:(NSUInteger)index;
49+
50+//- (void)removeChildAtIndex:(NSUInteger)index;
51+
52+//- (void)setChildren:(NSArray *)children;
53+
54+//- (void)addChild:(DDXMLNode *)child;
55+
56+//- (void)replaceChildAtIndex:(NSUInteger)index withNode:(DDXMLNode *)node;
57+
58+- (NSData *)XMLData;
59+- (NSData *)XMLDataWithOptions:(NSUInteger)options;
60+
61+//- (id)objectByApplyingXSLT:(NSData *)xslt arguments:(NSDictionary *)arguments error:(NSError **)error;
62+//- (id)objectByApplyingXSLTString:(NSString *)xslt arguments:(NSDictionary *)arguments error:(NSError **)error;
63+//- (id)objectByApplyingXSLTAtURL:(NSURL *)xsltURL arguments:(NSDictionary *)argument error:(NSError **)error;
64+
65+//- (BOOL)validateAndReturnError:(NSError **)error;
66+
67+@end
--- trunk/0.2.X/KissXML/DDXMLElement.m (nonexistent)
+++ trunk/0.2.X/KissXML/DDXMLElement.m (revision 274)
@@ -0,0 +1,671 @@
1+#import "DDXMLPrivate.h"
2+#import "NSString+DDXML.h"
3+
4+
5+@implementation DDXMLElement
6+
7+/**
8+ * Returns a DDXML wrapper object for the given primitive node.
9+ * The given node MUST be non-NULL and of the proper type.
10+**/
11++ (id)nodeWithElementPrimitive:(xmlNodePtr)node freeOnDealloc:(BOOL)flag
12+{
13+ return [[[DDXMLElement alloc] initWithElementPrimitive:node freeOnDealloc:flag] autorelease];
14+}
15+
16+- (id)initWithElementPrimitive:(xmlNodePtr)node freeOnDealloc:(BOOL)flag
17+{
18+ self = [super initWithPrimitive:(xmlKindPtr)node freeOnDealloc:flag];
19+ return self;
20+}
21+
22++ (id)nodeWithPrimitive:(xmlKindPtr)kindPtr freeOnDealloc:(BOOL)flag
23+{
24+ // Promote initializers which use proper parameter types to enable compiler to catch more mistakes
25+ NSAssert(NO, @"Use nodeWithElementPrimitive:freeOnDealloc:");
26+
27+ return nil;
28+}
29+
30+- (id)initWithPrimitive:(xmlKindPtr)kindPtr freeOnDealloc:(BOOL)flag
31+{
32+ // Promote initializers which use proper parameter types to enable compiler to catch more mistakes.
33+ NSAssert(NO, @"Use initWithElementPrimitive:freeOnDealloc:");
34+
35+ [self release];
36+ return nil;
37+}
38+
39+- (id)initWithName:(NSString *)name
40+{
41+ // Note: Make every guarantee that genericPtr is not null
42+
43+ xmlNodePtr node = xmlNewNode(NULL, [name xmlChar]);
44+ if (node == NULL)
45+ {
46+ [self release];
47+ return nil;
48+ }
49+
50+ return [self initWithElementPrimitive:node freeOnDealloc:YES];
51+}
52+
53+- (id)initWithName:(NSString *)name URI:(NSString *)URI
54+{
55+ // Note: Make every guarantee that genericPtr is not null
56+
57+ xmlNodePtr node = xmlNewNode(NULL, [name xmlChar]);
58+ if (node == NULL)
59+ {
60+ [self release];
61+ return nil;
62+ }
63+
64+ DDXMLElement *result = [self initWithElementPrimitive:node freeOnDealloc:YES];
65+ [result setURI:URI];
66+
67+ return result;
68+}
69+
70+- (id)initWithName:(NSString *)name stringValue:(NSString *)string
71+{
72+ // Note: Make every guarantee that genericPtr is not null
73+
74+ xmlNodePtr node = xmlNewNode(NULL, [name xmlChar]);
75+ if (node == NULL)
76+ {
77+ [self release];
78+ return nil;
79+ }
80+
81+ DDXMLElement *result = [self initWithElementPrimitive:node freeOnDealloc:YES];
82+ [result setStringValue:string];
83+
84+ return result;
85+}
86+
87+- (id)initWithXMLString:(NSString *)string error:(NSError **)error
88+{
89+ DDXMLDocument *doc = [[DDXMLDocument alloc] initWithXMLString:string options:0 error:error];
90+ if (doc == nil)
91+ {
92+ [self release];
93+ return nil;
94+ }
95+
96+ DDXMLElement *result = [doc rootElement];
97+ [result detach];
98+ [doc release];
99+
100+ [self release];
101+ return [result retain];
102+}
103+
104+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
105+#pragma mark Elements by name
106+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
107+
108+/**
109+ * Returns the child element nodes (as DDXMLElement objects) of the receiver that have a specified name.
110+ *
111+ * If name is a qualified name, then this method invokes elementsForLocalName:URI: with the URI parameter set to
112+ * the URI associated with the prefix. Otherwise comparison is based on string equality of the qualified or
113+ * non-qualified name.
114+**/
115+- (NSArray *)elementsForName:(NSString *)name
116+{
117+ if (name == nil) return [NSArray array];
118+
119+ // We need to check to see if name has a prefix.
120+ // If it does have a prefix, we need to figure out what the corresponding URI is for that prefix,
121+ // and then search for any elements that have the same name (including prefix) OR have the same URI.
122+ // Otherwise we loop through the children as usual and do a string compare on the name
123+
124+ NSString *prefix = [[self class] prefixForName:name];
125+ if ([prefix length] > 0)
126+ {
127+ xmlNodePtr node = (xmlNodePtr)genericPtr;
128+ xmlNsPtr ns = xmlSearchNs(node->doc, node, [prefix xmlChar]);
129+ if (ns != NULL)
130+ {
131+ NSString *uri = [NSString stringWithUTF8String:((const char *)ns->href)];
132+ return [self elementsForName:name uri:uri];
133+ }
134+
135+ // Note: We used xmlSearchNs instead of resolveNamespaceForName: because
136+ // we want to avoid creating wrapper objects when possible.
137+ }
138+
139+ return [self elementsForName:name uri:nil];
140+}
141+
142+- (NSArray *)elementsForLocalName:(NSString *)localName URI:(NSString *)URI
143+{
144+ if (localName == nil) return [NSArray array];
145+
146+ // We need to figure out what the prefix is for this URI.
147+ // Then we search for elements that are named prefix:localName OR (named localName AND have the given URI).
148+
149+ NSString *prefix = [self resolvePrefixForNamespaceURI:URI];
150+ if (prefix != nil)
151+ {
152+ NSString *name = [NSString stringWithFormat:@"%@:%@", prefix, localName];
153+
154+ return [self elementsForName:name uri:URI];
155+ }
156+ else
157+ {
158+ return [self elementsForName:localName uri:URI];
159+ }
160+}
161+
162+/**
163+ * Helper method elementsForName and elementsForLocalName:URI: so work isn't duplicated.
164+ * The name parameter is required, URI is optional.
165+**/
166+- (NSArray *)elementsForName:(NSString *)name uri:(NSString *)uri
167+{
168+ // Supplied: name, !uri : match: name
169+ // Supplied: p:name, uri : match: p:name || (name && uri)
170+ // Supplied: name, uri : match: name && uri
171+
172+ NSMutableArray *result = [NSMutableArray array];
173+
174+ xmlNodePtr node = (xmlNodePtr)genericPtr;
175+
176+ BOOL hasPrefix = [[[self class] prefixForName:name] length] > 0;
177+ NSString *localName = [[self class] localNameForName:name];
178+
179+ xmlNodePtr child = node->children;
180+ while (child != NULL)
181+ {
182+ if (child->type == XML_ELEMENT_NODE)
183+ {
184+ BOOL match = NO;
185+ if (uri == nil)
186+ {
187+ match = xmlStrEqual(child->name, [name xmlChar]);
188+ }
189+ else
190+ {
191+ BOOL nameMatch = xmlStrEqual(child->name, [name xmlChar]);
192+ BOOL localNameMatch = xmlStrEqual(child->name, [localName xmlChar]);
193+
194+ BOOL uriMatch = NO;
195+ if (child->ns != NULL)
196+ {
197+ uriMatch = xmlStrEqual(child->ns->href, [uri xmlChar]);
198+ }
199+
200+ if (hasPrefix)
201+ match = nameMatch || (localNameMatch && uriMatch);
202+ else
203+ match = nameMatch && uriMatch;
204+ }
205+
206+ if (match)
207+ {
208+ [result addObject:[DDXMLElement nodeWithElementPrimitive:child freeOnDealloc:NO]];
209+ }
210+ }
211+
212+ child = child->next;
213+ }
214+
215+ return result;
216+}
217+
218+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
219+#pragma mark Attributes
220+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
221+
222+- (BOOL)hasAttributeWithName:(NSString *)name
223+{
224+ xmlAttrPtr attr = ((xmlNodePtr)genericPtr)->properties;
225+ if (attr != NULL)
226+ {
227+ const xmlChar *xmlName = [name xmlChar];
228+
229+ do
230+ {
231+ if (xmlStrEqual(attr->name, xmlName))
232+ {
233+ return YES;
234+ }
235+ attr = attr->next;
236+
237+ } while (attr != NULL);
238+ }
239+
240+ return NO;
241+}
242+
243+- (void)addAttribute:(DDXMLNode *)attribute
244+{
245+ // NSXML version uses this same assertion
246+ DDXMLAssert([attribute hasParent] == NO, @"Cannot add an attribute with a parent; detach or copy first");
247+ DDXMLAssert(IsXmlAttrPtr(attribute->genericPtr), @"Not an attribute");
248+
249+ [self removeAttributeForName:[attribute name]];
250+
251+ // xmlNodePtr xmlAddChild(xmlNodePtr parent, xmlNodePtr cur)
252+ // Add a new node to @parent, at the end of the child (or property) list merging
253+ // adjacent TEXT nodes (in which case @cur is freed). If the new node is ATTRIBUTE, it is added
254+ // into properties instead of children. If there is an attribute with equal name, it is first destroyed.
255+
256+ xmlAddChild((xmlNodePtr)genericPtr, (xmlNodePtr)attribute->genericPtr);
257+
258+ // The attribute is now part of the xml tree heirarchy
259+ attribute->freeOnDealloc = NO;
260+}
261+
262+- (void)removeAttribute:(xmlAttrPtr)attr
263+{
264+ [[self class] removeAttribute:attr fromNode:(xmlNodePtr)genericPtr];
265+}
266+
267+- (void)removeAllAttributes
268+{
269+ [[self class] removeAllAttributesFromNode:(xmlNodePtr)genericPtr];
270+}
271+
272+- (void)removeAttributeForName:(NSString *)name
273+{
274+ xmlAttrPtr attr = ((xmlNodePtr)genericPtr)->properties;
275+ if (attr != NULL)
276+ {
277+ const xmlChar *xmlName = [name xmlChar];
278+
279+ do
280+ {
281+ if (xmlStrEqual(attr->name, xmlName))
282+ {
283+ [self removeAttribute:attr];
284+ return;
285+ }
286+ attr = attr->next;
287+
288+ } while(attr != NULL);
289+ }
290+}
291+
292+- (NSArray *)attributes
293+{
294+ NSMutableArray *result = [NSMutableArray array];
295+
296+ xmlAttrPtr attr = ((xmlNodePtr)genericPtr)->properties;
297+ while (attr != NULL)
298+ {
299+ [result addObject:[DDXMLAttributeNode nodeWithAttrPrimitive:attr freeOnDealloc:NO]];
300+
301+ attr = attr->next;
302+ }
303+
304+ return result;
305+}
306+
307+- (DDXMLNode *)attributeForName:(NSString *)name
308+{
309+ const xmlChar *attrName = [name xmlChar];
310+
311+ xmlAttrPtr attr = ((xmlNodePtr)genericPtr)->properties;
312+ while (attr != NULL)
313+ {
314+ if (attr->ns && attr->ns->prefix)
315+ {
316+ // If the attribute name was originally something like "xml:quack",
317+ // then attr->name is "quack" and attr->ns->prefix is "xml".
318+ //
319+ // So if the user is searching for "xml:quack" we need to take the prefix into account.
320+ // Note that "xml:quack" is what would be printed if we output the attribute.
321+
322+ if (xmlStrQEqual(attr->ns->prefix, attr->name, attrName))
323+ {
324+ return [DDXMLAttributeNode nodeWithAttrPrimitive:attr freeOnDealloc:NO];
325+ }
326+ }
327+ else
328+ {
329+ if (xmlStrEqual(attr->name, attrName))
330+ {
331+ return [DDXMLAttributeNode nodeWithAttrPrimitive:attr freeOnDealloc:NO];
332+ }
333+ }
334+
335+ attr = attr->next;
336+ }
337+ return nil;
338+}
339+
340+/**
341+ * Sets the list of attributes for the element.
342+ * Any previously set attributes are removed.
343+**/
344+- (void)setAttributes:(NSArray *)attributes
345+{
346+ [self removeAllAttributes];
347+
348+ NSUInteger i;
349+ for (i = 0; i < [attributes count]; i++)
350+ {
351+ DDXMLNode *attribute = [attributes objectAtIndex:i];
352+ [self addAttribute:attribute];
353+
354+ // Note: The addAttributes method properly sets the freeOnDealloc ivar.
355+ }
356+}
357+
358+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
359+#pragma mark Namespaces
360+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
361+
362+- (void)addNamespace:(DDXMLNode *)namespace
363+{
364+ // NSXML version uses this same assertion
365+ DDXMLAssert([namespace hasParent] == NO, @"Cannot add a namespace with a parent; detach or copy first");
366+ DDXMLAssert(IsXmlNsPtr(namespace->genericPtr), @"Not a namespace");
367+
368+ xmlNodePtr node = (xmlNodePtr)genericPtr;
369+ xmlNsPtr ns = (xmlNsPtr)namespace->genericPtr;
370+
371+ // Beware: [namespace prefix] does NOT return what you might expect. Use [namespace name] instead.
372+
373+ NSString *namespaceName = [namespace name];
374+
375+ [self removeNamespaceForPrefix:namespaceName];
376+
377+ xmlNsPtr currentNs = node->nsDef;
378+ if (currentNs == NULL)
379+ {
380+ node->nsDef = ns;
381+ }
382+ else
383+ {
384+ while (currentNs->next != NULL)
385+ {
386+ currentNs = currentNs->next;
387+ }
388+
389+ currentNs->next = ns;
390+ }
391+
392+ // The namespace is now part of the xml tree heirarchy
393+ namespace->freeOnDealloc = NO;
394+
395+ if ([namespace isKindOfClass:[DDXMLNamespaceNode class]])
396+ {
397+ DDXMLNamespaceNode *ddNamespace = (DDXMLNamespaceNode *)namespace;
398+
399+ // The xmlNs structure doesn't contain a reference to the parent, so we manage our own reference
400+ [ddNamespace setNsParentPtr:node];
401+ }
402+
403+ // Did we just add a default namespace
404+ if ([namespaceName isEqualToString:@""])
405+ {
406+ node->ns = ns;
407+
408+ // Note: The removeNamespaceForPrefix method above properly handled removing any previous default namespace
409+ }
410+}
411+
412+- (void)removeNamespace:(xmlNsPtr)ns
413+{
414+ [[self class] removeNamespace:ns fromNode:(xmlNodePtr)genericPtr];
415+}
416+
417+- (void)removeAllNamespaces
418+{
419+ [[self class] removeAllNamespacesFromNode:(xmlNodePtr)genericPtr];
420+}
421+
422+- (void)removeNamespaceForPrefix:(NSString *)name
423+{
424+ // If name is nil or the empty string, the user is wishing to remove the default namespace
425+ const xmlChar *xmlName = [name length] > 0 ? [name xmlChar] : NULL;
426+
427+ xmlNsPtr ns = ((xmlNodePtr)genericPtr)->nsDef;
428+ while (ns != NULL)
429+ {
430+ if (xmlStrEqual(ns->prefix, xmlName))
431+ {
432+ [self removeNamespace:ns];
433+ break;
434+ }
435+ ns = ns->next;
436+ }
437+
438+ // Note: The removeNamespace method properly handles the situation where the namespace is the default namespace
439+}
440+
441+- (NSArray *)namespaces
442+{
443+ NSMutableArray *result = [NSMutableArray array];
444+
445+ xmlNsPtr ns = ((xmlNodePtr)genericPtr)->nsDef;
446+ while (ns != NULL)
447+ {
448+ [result addObject:[DDXMLNamespaceNode nodeWithNsPrimitive:ns nsParent:(xmlNodePtr)genericPtr freeOnDealloc:NO]];
449+
450+ ns = ns->next;
451+ }
452+
453+ return result;
454+}
455+
456+- (DDXMLNode *)namespaceForPrefix:(NSString *)prefix
457+{
458+ // If the prefix is nil or the empty string, the user is requesting the default namespace
459+
460+ if ([prefix length] == 0)
461+ {
462+ // Requesting the default namespace
463+ xmlNsPtr ns = ((xmlNodePtr)genericPtr)->ns;
464+ if (ns != NULL)
465+ {
466+ return [DDXMLNamespaceNode nodeWithNsPrimitive:ns nsParent:(xmlNodePtr)genericPtr freeOnDealloc:NO];
467+ }
468+ }
469+ else
470+ {
471+ xmlNsPtr ns = ((xmlNodePtr)genericPtr)->nsDef;
472+ while (ns != NULL)
473+ {
474+ if (xmlStrEqual(ns->prefix, [prefix xmlChar]))
475+ {
476+ return [DDXMLNamespaceNode nodeWithNsPrimitive:ns nsParent:(xmlNodePtr)genericPtr freeOnDealloc:NO];
477+ }
478+ ns = ns->next;
479+ }
480+ }
481+
482+ return nil;
483+}
484+
485+- (void)setNamespaces:(NSArray *)namespaces
486+{
487+ [self removeAllNamespaces];
488+
489+ NSUInteger i;
490+ for (i = 0; i < [namespaces count]; i++)
491+ {
492+ DDXMLNode *namespace = [namespaces objectAtIndex:i];
493+ [self addNamespace:namespace];
494+
495+ // Note: The addNamespace method properly sets the freeOnDealloc ivar.
496+ }
497+}
498+
499+/**
500+ * Recursively searches the given node for the given namespace
501+**/
502++ (DDXMLNode *)resolveNamespaceForPrefix:(NSString *)prefix atNode:(xmlNodePtr)nodePtr
503+{
504+ if (nodePtr == NULL) return nil;
505+
506+ xmlNsPtr ns = nodePtr->nsDef;
507+ while (ns != NULL)
508+ {
509+ if (xmlStrEqual(ns->prefix, [prefix xmlChar]))
510+ {
511+ return [DDXMLNamespaceNode nodeWithNsPrimitive:ns nsParent:nodePtr freeOnDealloc:NO];
512+ }
513+ ns = ns->next;
514+ }
515+
516+ return [self resolveNamespaceForPrefix:prefix atNode:nodePtr->parent];
517+}
518+
519+/**
520+ * Returns the namespace node with the prefix matching the given qualified name.
521+ * Eg: You pass it "a:dog", it returns the namespace (defined in this node or parent nodes) that has the "a" prefix.
522+**/
523+- (DDXMLNode *)resolveNamespaceForName:(NSString *)name
524+{
525+ // If the user passes nil or an empty string for name, they're looking for the default namespace.
526+ if ([name length] == 0)
527+ {
528+ return [[self class] resolveNamespaceForPrefix:nil atNode:(xmlNodePtr)genericPtr];
529+ }
530+
531+ NSString *prefix = [[self class] prefixForName:name];
532+
533+ if ([prefix length] > 0)
534+ {
535+ // Unfortunately we can't use xmlSearchNs because it returns an xmlNsPtr.
536+ // This gives us mostly what we want, except we also need to know the nsParent.
537+ // So we do the recursive search ourselves.
538+
539+ return [[self class] resolveNamespaceForPrefix:prefix atNode:(xmlNodePtr)genericPtr];
540+ }
541+
542+ return nil;
543+}
544+
545+/**
546+ * Recursively searches the given node for a namespace with the given URI, and a set prefix.
547+**/
548++ (NSString *)resolvePrefixForURI:(NSString *)uri atNode:(xmlNodePtr)nodePtr
549+{
550+ if (nodePtr == NULL) return nil;
551+
552+ xmlNsPtr ns = nodePtr->nsDef;
553+ while (ns != NULL)
554+ {
555+ if (xmlStrEqual(ns->href, [uri xmlChar]))
556+ {
557+ if (ns->prefix != NULL)
558+ {
559+ return [NSString stringWithUTF8String:((const char *)ns->prefix)];
560+ }
561+ }
562+ ns = ns->next;
563+ }
564+
565+ return [self resolvePrefixForURI:uri atNode:nodePtr->parent];
566+}
567+
568+/**
569+ * Returns the prefix associated with the specified URI.
570+ * Returns a string that is the matching prefix or nil if it finds no matching prefix.
571+**/
572+- (NSString *)resolvePrefixForNamespaceURI:(NSString *)namespaceURI
573+{
574+ // We can't use xmlSearchNsByHref because it will return xmlNsPtr's with NULL prefixes.
575+ // We're looking for a definitive prefix for the given URI.
576+
577+ return [[self class] resolvePrefixForURI:namespaceURI atNode:(xmlNodePtr)genericPtr];
578+}
579+
580+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
581+#pragma mark Children
582+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
583+
584+- (void)addChild:(DDXMLNode *)child
585+{
586+ // NSXML version uses these same assertions
587+ DDXMLAssert([child hasParent] == NO, @"Cannot add a child that has a parent; detach or copy first");
588+ DDXMLAssert(IsXmlNodePtr(child->genericPtr),
589+ @"Elements can only have text, elements, processing instructions, and comments as children");
590+
591+ xmlAddChild((xmlNodePtr)genericPtr, (xmlNodePtr)child->genericPtr);
592+
593+ // The node is now part of the xml tree heirarchy
594+ child->freeOnDealloc = NO;
595+}
596+
597+- (void)insertChild:(DDXMLNode *)child atIndex:(NSUInteger)index
598+{
599+ // NSXML version uses these same assertions
600+ DDXMLAssert([child hasParent] == NO, @"Cannot add a child that has a parent; detach or copy first");
601+ DDXMLAssert(IsXmlNodePtr(child->genericPtr),
602+ @"Elements can only have text, elements, processing instructions, and comments as children");
603+
604+ NSUInteger i = 0;
605+
606+ xmlNodePtr childNodePtr = ((xmlNodePtr)genericPtr)->children;
607+ while (childNodePtr != NULL)
608+ {
609+ // Ignore all but element, comment, text, or processing instruction nodes
610+ if (IsXmlNodePtr(childNodePtr))
611+ {
612+ if (i == index)
613+ {
614+ xmlAddPrevSibling(childNodePtr, (xmlNodePtr)child->genericPtr);
615+ child->freeOnDealloc = NO;
616+ return;
617+ }
618+
619+ i++;
620+ }
621+ childNodePtr = childNodePtr->next;
622+ }
623+
624+ if (i == index)
625+ {
626+ xmlAddChild((xmlNodePtr)genericPtr, (xmlNodePtr)child->genericPtr);
627+ child->freeOnDealloc = NO;
628+ return;
629+ }
630+
631+ // NSXML version uses this same assertion
632+ DDXMLAssert(NO, @"index (%u) beyond bounds (%u)", (unsigned)index, (unsigned)++i);
633+}
634+
635+- (void)removeChildAtIndex:(NSUInteger)index
636+{
637+ NSUInteger i = 0;
638+
639+ xmlNodePtr child = ((xmlNodePtr)genericPtr)->children;
640+ while (child != NULL)
641+ {
642+ // Ignore all but element, comment, text, or processing instruction nodes
643+ if (IsXmlNodePtr(child))
644+ {
645+ if (i == index)
646+ {
647+ [DDXMLNode removeChild:child fromNode:(xmlNodePtr)genericPtr];
648+ return;
649+ }
650+
651+ i++;
652+ }
653+ child = child->next;
654+ }
655+}
656+
657+- (void)setChildren:(NSArray *)children
658+{
659+ [DDXMLNode removeAllChildrenFromNode:(xmlNodePtr)genericPtr];
660+
661+ NSUInteger i;
662+ for (i = 0; i < [children count]; i++)
663+ {
664+ DDXMLNode *child = [children objectAtIndex:i];
665+ [self addChild:child];
666+
667+ // Note: The addChild method properly sets the freeOnDealloc ivar.
668+ }
669+}
670+
671+@end
--- trunk/0.2.X/KissXML/Additions/DDXMLElementAdditions.h (nonexistent)
+++ trunk/0.2.X/KissXML/Additions/DDXMLElementAdditions.h (revision 274)
@@ -0,0 +1,21 @@
1+#import <Foundation/Foundation.h>
2+#import "DDXML.h"
3+
4+// These methods are not part of the standard NSXML API.
5+// But any developer working extensively with XML will likely appreciate them.
6+
7+@interface DDXMLElement (DDAdditions)
8+
9++ (DDXMLElement *)elementWithName:(NSString *)name xmlns:(NSString *)ns;
10+
11+- (DDXMLElement *)elementForName:(NSString *)name;
12+- (DDXMLElement *)elementForName:(NSString *)name xmlns:(NSString *)xmlns;
13+
14+- (NSString *)xmlns;
15+- (void)setXmlns:(NSString *)ns;
16+
17+- (void)addAttributeWithName:(NSString *)name stringValue:(NSString *)string;
18+
19+- (NSDictionary *)attributesAsDictionary;
20+
21+@end
--- trunk/0.2.X/KissXML/Additions/DDXMLElementAdditions.m (nonexistent)
+++ trunk/0.2.X/KissXML/Additions/DDXMLElementAdditions.m (revision 274)
@@ -0,0 +1,115 @@
1+#import "DDXMLElementAdditions.h"
2+
3+@implementation DDXMLElement (DDAdditions)
4+
5+/**
6+ * Quick method to create an element
7+**/
8++ (DDXMLElement *)elementWithName:(NSString *)name xmlns:(NSString *)ns
9+{
10+ DDXMLElement *element = [DDXMLElement elementWithName:name];
11+ [element setXmlns:ns];
12+ return element;
13+}
14+
15+/**
16+ * This method returns the first child element for the given name.
17+ * If no child element exists for the given name, returns nil.
18+**/
19+- (DDXMLElement *)elementForName:(NSString *)name
20+{
21+ NSArray *elements = [self elementsForName:name];
22+ if([elements count] > 0)
23+ {
24+ return [elements objectAtIndex:0];
25+ }
26+ else
27+ {
28+ // Note: If you port this code to work with Apple's NSXML, beware of the following:
29+ //
30+ // There is a bug in the NSXMLElement elementsForName: method.
31+ // Consider the following XML fragment:
32+ //
33+ // <query xmlns="jabber:iq:private">
34+ // <x xmlns="some:other:namespace"></x>
35+ // </query>
36+ //
37+ // Calling [query elementsForName:@"x"] results in an empty array!
38+ //
39+ // However, it will work properly if you use the following:
40+ // [query elementsForLocalName:@"x" URI:@"some:other:namespace"]
41+ //
42+ // The trouble with this is that we may not always know the xmlns in advance,
43+ // so in this particular case there is no way to access the element without looping through the children.
44+ //
45+ // This bug was submitted to apple on June 1st, 2007 and was classified as "serious".
46+ //
47+ // --!!-- This bug does NOT exist in DDXML --!!--
48+
49+ return nil;
50+ }
51+}
52+
53+/**
54+ * This method returns the first child element for the given name and given xmlns.
55+ * If no child elements exist for the given name and given xmlns, returns nil.
56+**/
57+- (DDXMLElement *)elementForName:(NSString *)name xmlns:(NSString *)xmlns
58+{
59+ NSArray *elements = [self elementsForLocalName:name URI:xmlns];
60+ if([elements count] > 0)
61+ {
62+ return [elements objectAtIndex:0];
63+ }
64+ else
65+ {
66+ return nil;
67+ }
68+}
69+
70+/**
71+ * Returns the common xmlns "attribute", which is only accessible via the namespace methods.
72+ * The xmlns value is often used in jabber elements.
73+**/
74+- (NSString *)xmlns
75+{
76+ return [[self namespaceForPrefix:@""] stringValue];
77+}
78+
79+- (void)setXmlns:(NSString *)ns
80+{
81+ // If you use setURI: then the xmlns won't be displayed in the XMLString.
82+ // Adding the namespace this way works properly.
83+ //
84+ // This applies to both Apple's NSXML and DDXML.
85+
86+ [self addNamespace:[DDXMLNode namespaceWithName:@"" stringValue:ns]];
87+}
88+
89+/**
90+ * Shortcut to avoid having to manually create a DDXMLNode everytime.
91+**/
92+- (void)addAttributeWithName:(NSString *)name stringValue:(NSString *)string
93+{
94+ [self addAttribute:[DDXMLNode attributeWithName:name stringValue:string]];
95+}
96+
97+/**
98+ * Returns all the attributes as a dictionary.
99+**/
100+- (NSDictionary *)attributesAsDictionary
101+{
102+ NSArray *attributes = [self attributes];
103+ NSMutableDictionary *result = [NSMutableDictionary dictionaryWithCapacity:[attributes count]];
104+
105+ uint i;
106+ for(i = 0; i < [attributes count]; i++)
107+ {
108+ DDXMLNode *node = [attributes objectAtIndex:i];
109+
110+ [result setObject:[node stringValue] forKey:[node name]];
111+ }
112+ return result;
113+}
114+
115+@end
--- trunk/0.2.X/KissXML/DDXML.h (nonexistent)
+++ trunk/0.2.X/KissXML/DDXML.h (revision 274)
@@ -0,0 +1,3 @@
1+#import "DDXMLNode.h"
2+#import "DDXMLElement.h"
3+#import "DDXMLDocument.h"
Afficher sur ancien navigateur de dépôt.