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