First Commit
This commit is contained in:
1 parent
1d4d9c2e6d
commit
d281d765ea
124 files changed
+41873
-9
No files matched your search
@@ -0,0 +1,24 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DDXML.h"
|
||||
|
||||
// These methods are not part of the standard NSXML API.
|
||||
// But any developer working extensively with XML will likely appreciate them.
|
||||
|
||||
@interface DDXMLElement (DDAdditions)
|
||||
|
||||
+ (DDXMLElement *)elementWithName:(NSString *)name xmlns:(NSString *)ns;
|
||||
|
||||
- (DDXMLElement *)elementForName:(NSString *)name;
|
||||
- (DDXMLElement *)elementForName:(NSString *)name xmlns:(NSString *)xmlns;
|
||||
|
||||
- (NSString *)xmlns;
|
||||
- (void)setXmlns:(NSString *)ns;
|
||||
|
||||
- (NSString *)prettyXMLString;
|
||||
- (NSString *)compactXMLString;
|
||||
|
||||
- (void)addAttributeWithName:(NSString *)name stringValue:(NSString *)string;
|
||||
|
||||
- (NSDictionary *)attributesAsDictionary;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,131 @@
|
||||
#import "DDXMLElementAdditions.h"
|
||||
|
||||
@implementation DDXMLElement (DDAdditions)
|
||||
|
||||
/**
|
||||
* Quick method to create an element
|
||||
**/
|
||||
+ (DDXMLElement *)elementWithName:(NSString *)name xmlns:(NSString *)ns
|
||||
{
|
||||
DDXMLElement *element = [DDXMLElement elementWithName:name];
|
||||
[element setXmlns:ns];
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the first child element for the given name.
|
||||
* If no child element exists for the given name, returns nil.
|
||||
**/
|
||||
- (DDXMLElement *)elementForName:(NSString *)name
|
||||
{
|
||||
NSArray *elements = [self elementsForName:name];
|
||||
if([elements count] > 0)
|
||||
{
|
||||
return [elements objectAtIndex:0];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Note: If you port this code to work with Apple's NSXML, beware of the following:
|
||||
//
|
||||
// There is a bug in the NSXMLElement elementsForName: method.
|
||||
// Consider the following XML fragment:
|
||||
//
|
||||
// <query xmlns="jabber:iq:private">
|
||||
// <x xmlns="some:other:namespace"></x>
|
||||
// </query>
|
||||
//
|
||||
// Calling [query elementsForName:@"x"] results in an empty array!
|
||||
//
|
||||
// However, it will work properly if you use the following:
|
||||
// [query elementsForLocalName:@"x" URI:@"some:other:namespace"]
|
||||
//
|
||||
// The trouble with this is that we may not always know the xmlns in advance,
|
||||
// so in this particular case there is no way to access the element without looping through the children.
|
||||
//
|
||||
// This bug was submitted to apple on June 1st, 2007 and was classified as "serious".
|
||||
//
|
||||
// --!!-- This bug does NOT exist in DDXML --!!--
|
||||
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the first child element for the given name and given xmlns.
|
||||
* If no child elements exist for the given name and given xmlns, returns nil.
|
||||
**/
|
||||
- (DDXMLElement *)elementForName:(NSString *)name xmlns:(NSString *)xmlns
|
||||
{
|
||||
NSArray *elements = [self elementsForLocalName:name URI:xmlns];
|
||||
if([elements count] > 0)
|
||||
{
|
||||
return [elements objectAtIndex:0];
|
||||
}
|
||||
else
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the common xmlns "attribute", which is only accessible via the namespace methods.
|
||||
* The xmlns value is often used in jabber elements.
|
||||
**/
|
||||
- (NSString *)xmlns
|
||||
{
|
||||
return [[self namespaceForPrefix:@""] stringValue];
|
||||
}
|
||||
|
||||
- (void)setXmlns:(NSString *)ns
|
||||
{
|
||||
// If you use setURI: then the xmlns won't be displayed in the XMLString.
|
||||
// Adding the namespace this way works properly.
|
||||
//
|
||||
// This applies to both Apple's NSXML and DDXML.
|
||||
|
||||
[self addNamespace:[DDXMLNode namespaceWithName:@"" stringValue:ns]];
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut to get a pretty (formatted) string representation of the element.
|
||||
**/
|
||||
- (NSString *)prettyXMLString
|
||||
{
|
||||
return [self XMLStringWithOptions:(DDXMLNodePrettyPrint | DDXMLNodeCompactEmptyElement)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut to get a compact string representation of the element.
|
||||
**/
|
||||
- (NSString *)compactXMLString
|
||||
{
|
||||
return [self XMLStringWithOptions:DDXMLNodeCompactEmptyElement];
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut to avoid having to manually create a DDXMLNode everytime.
|
||||
**/
|
||||
- (void)addAttributeWithName:(NSString *)name stringValue:(NSString *)string
|
||||
{
|
||||
[self addAttribute:[DDXMLNode attributeWithName:name stringValue:string]];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the attributes as a dictionary.
|
||||
**/
|
||||
- (NSDictionary *)attributesAsDictionary
|
||||
{
|
||||
NSArray *attributes = [self attributes];
|
||||
NSMutableDictionary *result = [NSMutableDictionary dictionaryWithCapacity:[attributes count]];
|
||||
|
||||
uint i;
|
||||
for(i = 0; i < [attributes count]; i++)
|
||||
{
|
||||
DDXMLNode *node = [attributes objectAtIndex:i];
|
||||
|
||||
[result setObject:[node stringValue] forKey:[node name]];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,24 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#if DDXML_LIBXML_MODULE_ENABLED
|
||||
#if TARGET_OS_IOS && TARGET_OS_EMBEDDED
|
||||
@import libxml;
|
||||
#elif TARGET_IPHONE_SIMULATOR
|
||||
@import libxmlSimu;
|
||||
#elif TARGET_OS_MAC
|
||||
@import libxmlMac;
|
||||
#endif
|
||||
#else
|
||||
#import <libxml/tree.h>
|
||||
#endif
|
||||
|
||||
@interface NSString (DDXML)
|
||||
|
||||
/**
|
||||
* xmlChar - A basic replacement for char, a byte in a UTF-8 encoded string.
|
||||
**/
|
||||
- (const xmlChar *)xmlChar;
|
||||
|
||||
- (NSString *)stringByTrimming;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,31 @@
|
||||
#import "NSString+DDXML.h"
|
||||
|
||||
#if ! __has_feature(objc_arc)
|
||||
#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
|
||||
#endif
|
||||
|
||||
@implementation NSString (DDXML)
|
||||
|
||||
- (const xmlChar *)xmlChar
|
||||
{
|
||||
return (const xmlChar *)[self UTF8String];
|
||||
}
|
||||
|
||||
#ifdef GNUSTEP
|
||||
- (NSString *)stringByTrimming
|
||||
{
|
||||
return [self stringByTrimmingSpaces];
|
||||
}
|
||||
#else
|
||||
- (NSString *)stringByTrimming
|
||||
{
|
||||
NSMutableString *mStr = [self mutableCopy];
|
||||
CFStringTrimWhitespace((__bridge CFMutableStringRef)mStr);
|
||||
|
||||
NSString *result = [mStr copy];
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
@end
|
||||
Generated
+194
@@ -0,0 +1,194 @@
|
||||
/**
|
||||
* Welcome to KissXML.
|
||||
*
|
||||
* The project page has documentation if you have questions.
|
||||
* https://github.com/robbiehanson/KissXML
|
||||
*
|
||||
* If you're new to the project you may wish to read the "Getting Started" wiki.
|
||||
* https://github.com/robbiehanson/KissXML/wiki/GettingStarted
|
||||
*
|
||||
* KissXML provides a drop-in replacement for Apple's NSXML class cluster.
|
||||
* The goal is to get the exact same behavior as the NSXML classes.
|
||||
*
|
||||
* For API Reference, see Apple's excellent documentation,
|
||||
* either via Xcode's Mac OS X documentation, or via the web:
|
||||
*
|
||||
* https://github.com/robbiehanson/KissXML/wiki/Reference
|
||||
**/
|
||||
|
||||
#import "DDXMLNode.h"
|
||||
#import "DDXMLElement.h"
|
||||
#import "DDXMLDocument.h"
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
// Since KissXML is a drop in replacement for NSXML,
|
||||
// it may be desireable (when writing cross-platform code to be used on both Mac OS X and iOS)
|
||||
// to use the NSXML prefixes instead of the DDXML prefix.
|
||||
//
|
||||
// This way, on Mac OS X it uses NSXML, and on iOS it uses KissXML.
|
||||
|
||||
#ifndef NSXMLNode
|
||||
#define NSXMLNode DDXMLNode
|
||||
#endif
|
||||
#ifndef NSXMLElement
|
||||
#define NSXMLElement DDXMLElement
|
||||
#endif
|
||||
#ifndef NSXMLDocument
|
||||
#define NSXMLDocument DDXMLDocument
|
||||
#endif
|
||||
|
||||
#ifndef NSXMLInvalidKind
|
||||
#define NSXMLInvalidKind DDXMLInvalidKind
|
||||
#endif
|
||||
#ifndef NSXMLDocumentKind
|
||||
#define NSXMLDocumentKind DDXMLDocumentKind
|
||||
#endif
|
||||
#ifndef NSXMLElementKind
|
||||
#define NSXMLElementKind DDXMLElementKind
|
||||
#endif
|
||||
#ifndef NSXMLAttributeKind
|
||||
#define NSXMLAttributeKind DDXMLAttributeKind
|
||||
#endif
|
||||
#ifndef NSXMLNamespaceKind
|
||||
#define NSXMLNamespaceKind DDXMLNamespaceKind
|
||||
#endif
|
||||
#ifndef NSXMLProcessingInstructionKind
|
||||
#define NSXMLProcessingInstructionKind DDXMLProcessingInstructionKind
|
||||
#endif
|
||||
#ifndef NSXMLCommentKind
|
||||
#define NSXMLCommentKind DDXMLCommentKind
|
||||
#endif
|
||||
#ifndef NSXMLTextKind
|
||||
#define NSXMLTextKind DDXMLTextKind
|
||||
#endif
|
||||
#ifndef NSXMLDTDKind
|
||||
#define NSXMLDTDKind DDXMLDTDKind
|
||||
#endif
|
||||
#ifndef NSXMLEntityDeclarationKind
|
||||
#define NSXMLEntityDeclarationKind DDXMLEntityDeclarationKind
|
||||
#endif
|
||||
#ifndef NSXMLAttributeDeclarationKind
|
||||
#define NSXMLAttributeDeclarationKind DDXMLAttributeDeclarationKind
|
||||
#endif
|
||||
#ifndef NSXMLElementDeclarationKind
|
||||
#define NSXMLElementDeclarationKind DDXMLElementDeclarationKind
|
||||
#endif
|
||||
#ifndef NSXMLNotationDeclarationKind
|
||||
#define NSXMLNotationDeclarationKind DDXMLNotationDeclarationKind
|
||||
#endif
|
||||
|
||||
#ifndef NSXMLNodeOptionsNone
|
||||
#define NSXMLNodeOptionsNone DDXMLNodeOptionsNone
|
||||
#endif
|
||||
#ifndef NSXMLNodeExpandEmptyElement
|
||||
#define NSXMLNodeExpandEmptyElement DDXMLNodeExpandEmptyElement
|
||||
#endif
|
||||
#ifndef NSXMLNodeCompactEmptyElement
|
||||
#define NSXMLNodeCompactEmptyElement DDXMLNodeCompactEmptyElement
|
||||
#endif
|
||||
#ifndef NSXMLNodePrettyPrint
|
||||
#define NSXMLNodePrettyPrint DDXMLNodePrettyPrint
|
||||
#endif
|
||||
|
||||
#endif // #if TARGET_OS_IPHONE
|
||||
|
||||
|
||||
|
||||
// KissXML has rather straight-forward memory management:
|
||||
// https://github.com/robbiehanson/KissXML/wiki/MemoryManagementThreadSafety
|
||||
//
|
||||
// There are 3 important concepts to keep in mind when working with KissXML:
|
||||
//
|
||||
//
|
||||
// 1.) KissXML provides a light-weight wrapper around libxml.
|
||||
//
|
||||
// The parsing, creation, storage, etc of the xml tree is all done via libxml.
|
||||
// This is a fast low-level C library that's been around for ages, and comes pre-installed on Mac OS X and iOS.
|
||||
// KissXML provides an easy-to-use Objective-C library atop libxml.
|
||||
// So a DDXMLNode, DDXMLElement, or DDXMLDocument are simply objective-c objects
|
||||
// with pointers to the underlying libxml C structure.
|
||||
// Then only time you need to be aware of any of this is when it comes to equality.
|
||||
// In order to maximize speed and provide read-access thread-safety,
|
||||
// the library may create multiple DDXML wrapper objects that point to the same underlying xml node.
|
||||
// So don't assume you can test for equality with "==".
|
||||
// Instead use the isEqual method (as you should generally do with objects anyway).
|
||||
//
|
||||
//
|
||||
// 2.) XML is implicitly a tree heirarchy, and the XML API's are designed to allow traversal up & down the tree.
|
||||
//
|
||||
// The tree heirarchy and API contract have an implicit impact concerning memory management.
|
||||
//
|
||||
// <starbucks>
|
||||
// <latte/>
|
||||
// </starbucks>
|
||||
//
|
||||
// Imagine you have a DDXMLNode corresponding to the starbucks node,
|
||||
// and you have a DDXMLNode corresponding to the latte node.
|
||||
// Now imagine you release the starbucks node, but you retain a reference to the latte node.
|
||||
// What happens?
|
||||
// Well the latte node is a part of the xml tree heirarchy.
|
||||
// So if the latte node is still around, the xml tree heirarchy must stick around as well.
|
||||
// So even though the DDXMLNode corresponding to the starbucks node may get deallocated,
|
||||
// the underlying xml tree structure won't be freed until the latte node gets dealloacated.
|
||||
//
|
||||
// In general, this means that KissXML remains thread-safe when reading and processing a tree.
|
||||
// If you traverse a tree and fork off asynchronous tasks to process subnodes,
|
||||
// the tree will remain properly in place until all your asynchronous tasks have completed.
|
||||
// In other words, it just works.
|
||||
//
|
||||
// However, if you parse a huge document into memory, and retain a single node from the giant xml tree...
|
||||
// Well you should see the problem this creates.
|
||||
// Instead, in this situation, copy or detach the node if you want to keep it around.
|
||||
// Or just extract the info you need from it.
|
||||
//
|
||||
//
|
||||
// 3.) KissXML is read-access thread-safe, but write-access thread-unsafe (designed for speed).
|
||||
//
|
||||
// <starbucks>
|
||||
// <latte/>
|
||||
// </starbucks>
|
||||
//
|
||||
// Imagine you have a DDXMLNode corresponding to the starbucks node,
|
||||
// and you have a DDXMLNode corresponding to the latte node.
|
||||
// What happens if you invoke [starbucks removeChildAtIndex:0]?
|
||||
// Well the undelying xml tree will remove the latte node, and release the associated memory.
|
||||
// And what if you still have a reference to the DDXMLNode that corresponds to the latte node?
|
||||
// Well the short answer is that you shouldn't use it. At all.
|
||||
// This is pretty obvious when you think about it from the context of this simple example.
|
||||
// But in the real world, you might have multiple threads running in parallel,
|
||||
// and you might accidently modify a node while another thread is processing it.
|
||||
//
|
||||
// To completely fix this problem, and provide write-access thread-safety, would require extensive overhead.
|
||||
// This overhead is completely unwanted in the majority of cases.
|
||||
// Most XML usage patterns are heavily read-only.
|
||||
// And in the case of xml creation or modification, it is generally done on the same thread.
|
||||
// Thus the KissXML library is write-access thread-unsafe, but provides speedier performance.
|
||||
//
|
||||
// However, when such a bug does creep up, it produces horrible side-effects.
|
||||
// Essentially the pointer to the underlying xml structure becomes a dangling pointer,
|
||||
// which means that accessing the dangling pointer might give you the correct results, or completely random results.
|
||||
// And attempting to make modifications to non-existant xml nodes via the dangling pointer might do nothing,
|
||||
// or completely corrupt your heap and cause un-explainable crashes in random parts of your library.
|
||||
// Heap corruption is one of the worst problems to track down.
|
||||
// So to help out, the library provides a debugging macro to track down these problems.
|
||||
// That is, if you invalidate the write-access thread-unsafe rule,
|
||||
// this macro will tell you when you're trying to access a now-dangling pointer.
|
||||
//
|
||||
// How does it work?
|
||||
// Well everytime a DDXML wrapper object is created atop a libxml structure,
|
||||
// it marks the linkage in a table.
|
||||
// And everytime a libxml structure is freed, it destorys all corresponding linkages in the table.
|
||||
// So everytime a DDXML wrapper objects is about to dereference it's pointer,
|
||||
// it first ensures the linkage still exists in the table.
|
||||
//
|
||||
// Set to 1 to enable
|
||||
// Set to 0 to disable (this is the default)
|
||||
//
|
||||
// The debugging macro adds a significant amount of overhead, and should NOT be enabled on production builds.
|
||||
|
||||
#if DEBUG
|
||||
#define DDXML_DEBUG_MEMORY_ISSUES 0
|
||||
#else
|
||||
#define DDXML_DEBUG_MEMORY_ISSUES 0 // Don't change me!
|
||||
#endif
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DDXMLElement.h"
|
||||
#import "DDXMLNode.h"
|
||||
|
||||
/**
|
||||
* Welcome to KissXML.
|
||||
*
|
||||
* The project page has documentation if you have questions.
|
||||
* https://github.com/robbiehanson/KissXML
|
||||
*
|
||||
* If you're new to the project you may wish to read the "Getting Started" wiki.
|
||||
* https://github.com/robbiehanson/KissXML/wiki/GettingStarted
|
||||
*
|
||||
* KissXML provides a drop-in replacement for Apple's NSXML class cluster.
|
||||
* The goal is to get the exact same behavior as the NSXML classes.
|
||||
*
|
||||
* For API Reference, see Apple's excellent documentation,
|
||||
* either via Xcode's Mac OS X documentation, or via the web:
|
||||
*
|
||||
* https://github.com/robbiehanson/KissXML/wiki/Reference
|
||||
**/
|
||||
|
||||
enum {
|
||||
DDXMLDocumentXMLKind = 0,
|
||||
DDXMLDocumentXHTMLKind,
|
||||
DDXMLDocumentHTMLKind,
|
||||
DDXMLDocumentTextKind
|
||||
};
|
||||
typedef NSUInteger DDXMLDocumentContentKind;
|
||||
|
||||
@interface DDXMLDocument : DDXMLNode
|
||||
{
|
||||
}
|
||||
|
||||
- (id)initWithXMLString:(NSString *)string options:(NSUInteger)mask error:(NSError **)error;
|
||||
//- (id)initWithContentsOfURL:(NSURL *)url options:(NSUInteger)mask error:(NSError **)error;
|
||||
- (id)initWithData:(NSData *)data options:(NSUInteger)mask error:(NSError **)error;
|
||||
//- (id)initWithRootElement:(DDXMLElement *)element;
|
||||
|
||||
//+ (Class)replacementClassForClass:(Class)cls;
|
||||
|
||||
//- (void)setCharacterEncoding:(NSString *)encoding; //primitive
|
||||
//- (NSString *)characterEncoding; //primitive
|
||||
|
||||
//- (void)setVersion:(NSString *)version;
|
||||
//- (NSString *)version;
|
||||
|
||||
//- (void)setStandalone:(BOOL)standalone;
|
||||
//- (BOOL)isStandalone;
|
||||
|
||||
//- (void)setDocumentContentKind:(DDXMLDocumentContentKind)kind;
|
||||
//- (DDXMLDocumentContentKind)documentContentKind;
|
||||
|
||||
//- (void)setMIMEType:(NSString *)MIMEType;
|
||||
//- (NSString *)MIMEType;
|
||||
|
||||
//- (void)setDTD:(DDXMLDTD *)documentTypeDeclaration;
|
||||
//- (DDXMLDTD *)DTD;
|
||||
|
||||
//- (void)setRootElement:(DDXMLNode *)root;
|
||||
- (DDXMLElement *)rootElement;
|
||||
|
||||
//- (void)insertChild:(DDXMLNode *)child atIndex:(NSUInteger)index;
|
||||
|
||||
//- (void)insertChildren:(NSArray *)children atIndex:(NSUInteger)index;
|
||||
|
||||
//- (void)removeChildAtIndex:(NSUInteger)index;
|
||||
|
||||
//- (void)setChildren:(NSArray *)children;
|
||||
|
||||
//- (void)addChild:(DDXMLNode *)child;
|
||||
|
||||
//- (void)replaceChildAtIndex:(NSUInteger)index withNode:(DDXMLNode *)node;
|
||||
|
||||
- (NSData *)XMLData;
|
||||
- (NSData *)XMLDataWithOptions:(NSUInteger)options;
|
||||
|
||||
//- (id)objectByApplyingXSLT:(NSData *)xslt arguments:(NSDictionary *)arguments error:(NSError **)error;
|
||||
//- (id)objectByApplyingXSLTString:(NSString *)xslt arguments:(NSDictionary *)arguments error:(NSError **)error;
|
||||
//- (id)objectByApplyingXSLTAtURL:(NSURL *)xsltURL arguments:(NSDictionary *)argument error:(NSError **)error;
|
||||
|
||||
//- (BOOL)validateAndReturnError:(NSError **)error;
|
||||
|
||||
@end
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
#import "DDXMLPrivate.h"
|
||||
#import "NSString+DDXML.h"
|
||||
|
||||
#if ! __has_feature(objc_arc)
|
||||
#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Welcome to KissXML.
|
||||
*
|
||||
* The project page has documentation if you have questions.
|
||||
* https://github.com/robbiehanson/KissXML
|
||||
*
|
||||
* If you're new to the project you may wish to read the "Getting Started" wiki.
|
||||
* https://github.com/robbiehanson/KissXML/wiki/GettingStarted
|
||||
*
|
||||
* KissXML provides a drop-in replacement for Apple's NSXML class cluster.
|
||||
* The goal is to get the exact same behavior as the NSXML classes.
|
||||
*
|
||||
* For API Reference, see Apple's excellent documentation,
|
||||
* either via Xcode's Mac OS X documentation, or via the web:
|
||||
*
|
||||
* https://github.com/robbiehanson/KissXML/wiki/Reference
|
||||
**/
|
||||
|
||||
@implementation DDXMLDocument
|
||||
|
||||
/**
|
||||
* Returns a DDXML wrapper object for the given primitive node.
|
||||
* The given node MUST be non-NULL and of the proper type.
|
||||
**/
|
||||
+ (id)nodeWithDocPrimitive:(xmlDocPtr)doc owner:(DDXMLNode *)owner
|
||||
{
|
||||
return [[DDXMLDocument alloc] initWithDocPrimitive:doc owner:owner];
|
||||
}
|
||||
|
||||
- (id)initWithDocPrimitive:(xmlDocPtr)doc owner:(DDXMLNode *)inOwner
|
||||
{
|
||||
self = [super initWithPrimitive:(xmlKindPtr)doc owner:inOwner];
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (id)nodeWithPrimitive:(xmlKindPtr)kindPtr owner:(DDXMLNode *)owner
|
||||
{
|
||||
// Promote initializers which use proper parameter types to enable compiler to catch more mistakes
|
||||
NSAssert(NO, @"Use nodeWithDocPrimitive:owner:");
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (id)initWithPrimitive:(xmlKindPtr)kindPtr owner:(DDXMLNode *)inOwner
|
||||
{
|
||||
// Promote initializers which use proper parameter types to enable compiler to catch more mistakes.
|
||||
NSAssert(NO, @"Use initWithDocPrimitive:owner:");
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes and returns a DDXMLDocument object created from an NSData object.
|
||||
*
|
||||
* Returns an initialized DDXMLDocument object, or nil if initialization fails
|
||||
* because of parsing errors or other reasons.
|
||||
**/
|
||||
- (id)initWithXMLString:(NSString *)string options:(NSUInteger)mask error:(NSError **)error
|
||||
{
|
||||
return [self initWithData:[string dataUsingEncoding:NSUTF8StringEncoding]
|
||||
options:mask
|
||||
error:error];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes and returns a DDXMLDocument object created from an NSData object.
|
||||
*
|
||||
* Returns an initialized DDXMLDocument object, or nil if initialization fails
|
||||
* because of parsing errors or other reasons.
|
||||
**/
|
||||
- (id)initWithData:(NSData *)data options:(NSUInteger)mask error:(NSError **)error
|
||||
{
|
||||
if (data == nil || [data length] == 0)
|
||||
{
|
||||
if (error) *error = [NSError errorWithDomain:@"DDXMLErrorDomain" code:0 userInfo:nil];
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Even though xmlKeepBlanksDefault(0) is called in DDXMLNode's initialize method,
|
||||
// it has been documented that this call seems to get reset on the iPhone:
|
||||
// http://code.google.com/p/kissxml/issues/detail?id=8
|
||||
//
|
||||
// Therefore, we call it again here just to be safe.
|
||||
xmlKeepBlanksDefault(0);
|
||||
|
||||
xmlDocPtr doc = xmlParseMemory([data bytes], (int)[data length]);
|
||||
if (doc == NULL)
|
||||
{
|
||||
if (error) *error = [NSError errorWithDomain:@"DDXMLErrorDomain" code:1 userInfo:nil];
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [self initWithDocPrimitive:doc owner:nil];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the root element of the receiver.
|
||||
**/
|
||||
- (DDXMLElement *)rootElement
|
||||
{
|
||||
#if DDXML_DEBUG_MEMORY_ISSUES
|
||||
DDXMLNotZombieAssert();
|
||||
#endif
|
||||
|
||||
xmlDocPtr doc = (xmlDocPtr)genericPtr;
|
||||
|
||||
// doc->children is a list containing possibly comments, DTDs, etc...
|
||||
|
||||
xmlNodePtr rootNode = xmlDocGetRootElement(doc);
|
||||
|
||||
if (rootNode != NULL)
|
||||
return [DDXMLElement nodeWithElementPrimitive:rootNode owner:self];
|
||||
else
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSData *)XMLData
|
||||
{
|
||||
// Zombie test occurs in XMLString
|
||||
|
||||
return [[self XMLString] dataUsingEncoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
- (NSData *)XMLDataWithOptions:(NSUInteger)options
|
||||
{
|
||||
// Zombie test occurs in XMLString
|
||||
|
||||
return [[self XMLStringWithOptions:options] dataUsingEncoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
@end
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DDXMLNode.h"
|
||||
|
||||
/**
|
||||
* Welcome to KissXML.
|
||||
*
|
||||
* The project page has documentation if you have questions.
|
||||
* https://github.com/robbiehanson/KissXML
|
||||
*
|
||||
* If you're new to the project you may wish to read the "Getting Started" wiki.
|
||||
* https://github.com/robbiehanson/KissXML/wiki/GettingStarted
|
||||
*
|
||||
* KissXML provides a drop-in replacement for Apple's NSXML class cluster.
|
||||
* The goal is to get the exact same behavior as the NSXML classes.
|
||||
*
|
||||
* For API Reference, see Apple's excellent documentation,
|
||||
* either via Xcode's Mac OS X documentation, or via the web:
|
||||
*
|
||||
* https://github.com/robbiehanson/KissXML/wiki/Reference
|
||||
**/
|
||||
|
||||
@interface DDXMLElement : DDXMLNode
|
||||
{
|
||||
}
|
||||
|
||||
- (id)initWithName:(NSString *)name;
|
||||
- (id)initWithName:(NSString *)name URI:(NSString *)URI;
|
||||
- (id)initWithName:(NSString *)name stringValue:(NSString *)string;
|
||||
- (id)initWithXMLString:(NSString *)string error:(NSError **)error;
|
||||
|
||||
#pragma mark --- Elements by name ---
|
||||
|
||||
- (NSArray *)elementsForName:(NSString *)name;
|
||||
- (NSArray *)elementsForLocalName:(NSString *)localName URI:(NSString *)URI;
|
||||
|
||||
#pragma mark --- Attributes ---
|
||||
|
||||
- (void)addAttribute:(DDXMLNode *)attribute;
|
||||
- (void)removeAttributeForName:(NSString *)name;
|
||||
- (void)setAttributes:(NSArray *)attributes;
|
||||
//- (void)setAttributesAsDictionary:(NSDictionary *)attributes;
|
||||
- (NSArray *)attributes;
|
||||
- (DDXMLNode *)attributeForName:(NSString *)name;
|
||||
//- (DDXMLNode *)attributeForLocalName:(NSString *)localName URI:(NSString *)URI;
|
||||
|
||||
#pragma mark --- Namespaces ---
|
||||
|
||||
- (void)addNamespace:(DDXMLNode *)aNamespace;
|
||||
- (void)removeNamespaceForPrefix:(NSString *)name;
|
||||
- (void)setNamespaces:(NSArray *)namespaces;
|
||||
- (NSArray *)namespaces;
|
||||
- (DDXMLNode *)namespaceForPrefix:(NSString *)prefix;
|
||||
- (DDXMLNode *)resolveNamespaceForName:(NSString *)name;
|
||||
- (NSString *)resolvePrefixForNamespaceURI:(NSString *)namespaceURI;
|
||||
|
||||
#pragma mark --- Children ---
|
||||
|
||||
- (void)insertChild:(DDXMLNode *)child atIndex:(NSUInteger)index;
|
||||
//- (void)insertChildren:(NSArray *)children atIndex:(NSUInteger)index;
|
||||
- (void)removeChildAtIndex:(NSUInteger)index;
|
||||
- (void)setChildren:(NSArray *)children;
|
||||
- (void)addChild:(DDXMLNode *)child;
|
||||
//- (void)replaceChildAtIndex:(NSUInteger)index withNode:(DDXMLNode *)node;
|
||||
//- (void)normalizeAdjacentTextNodesPreservingCDATA:(BOOL)preserve;
|
||||
|
||||
@end
|
||||
+801
@@ -0,0 +1,801 @@
|
||||
#import "DDXMLPrivate.h"
|
||||
#import "NSString+DDXML.h"
|
||||
|
||||
#if ! __has_feature(objc_arc)
|
||||
#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Welcome to KissXML.
|
||||
*
|
||||
* The project page has documentation if you have questions.
|
||||
* https://github.com/robbiehanson/KissXML
|
||||
*
|
||||
* If you're new to the project you may wish to read the "Getting Started" wiki.
|
||||
* https://github.com/robbiehanson/KissXML/wiki/GettingStarted
|
||||
*
|
||||
* KissXML provides a drop-in replacement for Apple's NSXML class cluster.
|
||||
* The goal is to get the exact same behavior as the NSXML classes.
|
||||
*
|
||||
* For API Reference, see Apple's excellent documentation,
|
||||
* either via Xcode's Mac OS X documentation, or via the web:
|
||||
*
|
||||
* https://github.com/robbiehanson/KissXML/wiki/Reference
|
||||
**/
|
||||
|
||||
@implementation DDXMLElement
|
||||
|
||||
/**
|
||||
* Returns a DDXML wrapper object for the given primitive node.
|
||||
* The given node MUST be non-NULL and of the proper type.
|
||||
**/
|
||||
+ (id)nodeWithElementPrimitive:(xmlNodePtr)node owner:(DDXMLNode *)owner
|
||||
{
|
||||
return [[DDXMLElement alloc] initWithElementPrimitive:node owner:owner];
|
||||
}
|
||||
|
||||
- (id)initWithElementPrimitive:(xmlNodePtr)node owner:(DDXMLNode *)inOwner
|
||||
{
|
||||
self = [super initWithPrimitive:(xmlKindPtr)node owner:inOwner];
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (id)nodeWithPrimitive:(xmlKindPtr)kindPtr owner:(DDXMLNode *)owner
|
||||
{
|
||||
// Promote initializers which use proper parameter types to enable compiler to catch more mistakes
|
||||
NSAssert(NO, @"Use nodeWithElementPrimitive:owner:");
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (id)initWithPrimitive:(xmlKindPtr)kindPtr owner:(DDXMLNode *)inOwner
|
||||
{
|
||||
// Promote initializers which use proper parameter types to enable compiler to catch more mistakes.
|
||||
NSAssert(NO, @"Use initWithElementPrimitive:owner:");
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (id)initWithName:(NSString *)name
|
||||
{
|
||||
// Note: Make every guarantee that genericPtr is not null
|
||||
|
||||
xmlNodePtr node = xmlNewNode(NULL, [name xmlChar]);
|
||||
if (node == NULL)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [self initWithElementPrimitive:node owner:nil];
|
||||
}
|
||||
|
||||
- (id)initWithName:(NSString *)name URI:(NSString *)URI
|
||||
{
|
||||
// Note: Make every guarantee that genericPtr is not null
|
||||
|
||||
xmlNodePtr node = xmlNewNode(NULL, [name xmlChar]);
|
||||
if (node == NULL)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
DDXMLElement *result = [self initWithElementPrimitive:node owner:nil];
|
||||
[result setURI:URI];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (id)initWithName:(NSString *)name stringValue:(NSString *)string
|
||||
{
|
||||
// Note: Make every guarantee that genericPtr is not null
|
||||
|
||||
xmlNodePtr node = xmlNewNode(NULL, [name xmlChar]);
|
||||
if (node == NULL)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
DDXMLElement *result = [self initWithElementPrimitive:node owner:nil];
|
||||
[result setStringValue:string];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (id)initWithXMLString:(NSString *)string error:(NSError **)error
|
||||
{
|
||||
DDXMLDocument *doc = [[DDXMLDocument alloc] initWithXMLString:string options:0 error:error];
|
||||
if (doc == nil)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
DDXMLElement *result = [doc rootElement];
|
||||
[result detach];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark Elements by name
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Helper method elementsForName and elementsForLocalName:URI: so work isn't duplicated.
|
||||
* The name parameter is required, all others are optional.
|
||||
**/
|
||||
- (NSArray *)_elementsForName:(NSString *)name
|
||||
localName:(NSString *)localName
|
||||
prefix:(NSString *)prefix
|
||||
uri:(NSString *)uri
|
||||
{
|
||||
// This is a private/internal method
|
||||
|
||||
// Rule : !uri => match: name
|
||||
// Rule : uri && hasPrefix => match: name || (localName && uri)
|
||||
// Rule : uri && !hasPefix => match: name && uri
|
||||
|
||||
xmlNodePtr node = (xmlNodePtr)genericPtr;
|
||||
|
||||
NSMutableArray *result = [NSMutableArray array];
|
||||
|
||||
BOOL hasPrefix = [prefix length] > 0;
|
||||
|
||||
const xmlChar *xmlName = [name xmlChar];
|
||||
const xmlChar *xmlLocalName = [localName xmlChar];
|
||||
const xmlChar *xmlUri = [uri xmlChar];
|
||||
|
||||
xmlNodePtr child = node->children;
|
||||
while (child)
|
||||
{
|
||||
if (IsXmlNodePtr(child))
|
||||
{
|
||||
BOOL match = NO;
|
||||
|
||||
if (uri == nil)
|
||||
{
|
||||
match = xmlStrEqual(child->name, xmlName);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOL nameMatch = xmlStrEqual(child->name, xmlName);
|
||||
BOOL localNameMatch = xmlStrEqual(child->name, xmlLocalName);
|
||||
|
||||
BOOL uriMatch = NO;
|
||||
if (child->ns)
|
||||
{
|
||||
uriMatch = xmlStrEqual(child->ns->href, xmlUri);
|
||||
}
|
||||
|
||||
if (hasPrefix)
|
||||
match = nameMatch || (localNameMatch && uriMatch);
|
||||
else
|
||||
match = nameMatch && uriMatch;
|
||||
}
|
||||
|
||||
if (match)
|
||||
{
|
||||
[result addObject:[DDXMLElement nodeWithElementPrimitive:child owner:self]];
|
||||
}
|
||||
}
|
||||
|
||||
child = child->next;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the child element nodes (as DDXMLElement objects) of the receiver that have a specified name.
|
||||
*
|
||||
* If name is a qualified name, then this method invokes elementsForLocalName:URI: with the URI parameter set to
|
||||
* the URI associated with the prefix. Otherwise comparison is based on string equality of the qualified or
|
||||
* non-qualified name.
|
||||
**/
|
||||
- (NSArray *)elementsForName:(NSString *)name
|
||||
{
|
||||
#if DDXML_DEBUG_MEMORY_ISSUES
|
||||
DDXMLNotZombieAssert();
|
||||
#endif
|
||||
|
||||
if (name == nil) return [NSArray array];
|
||||
|
||||
// We need to check to see if name has a prefix.
|
||||
// If it does have a prefix, we need to figure out what the corresponding URI is for that prefix,
|
||||
// and then search for any elements that have the same name (including prefix) OR have the same URI.
|
||||
// Otherwise we loop through the children as usual and do a string compare on the name
|
||||
|
||||
NSString *prefix;
|
||||
NSString *localName;
|
||||
|
||||
[DDXMLNode getPrefix:&prefix localName:&localName forName:name];
|
||||
|
||||
if ([prefix length] > 0)
|
||||
{
|
||||
xmlNodePtr node = (xmlNodePtr)genericPtr;
|
||||
|
||||
// Note: We use xmlSearchNs instead of resolveNamespaceForName: because
|
||||
// we want to avoid creating wrapper objects when possible.
|
||||
|
||||
xmlNsPtr ns = xmlSearchNs(node->doc, node, [prefix xmlChar]);
|
||||
if (ns)
|
||||
{
|
||||
NSString *uri = [NSString stringWithUTF8String:((const char *)ns->href)];
|
||||
return [self _elementsForName:name localName:localName prefix:prefix uri:uri];
|
||||
}
|
||||
}
|
||||
|
||||
return [self _elementsForName:name localName:localName prefix:prefix uri:nil];
|
||||
}
|
||||
|
||||
- (NSArray *)elementsForLocalName:(NSString *)localName URI:(NSString *)uri
|
||||
{
|
||||
#if DDXML_DEBUG_MEMORY_ISSUES
|
||||
DDXMLNotZombieAssert();
|
||||
#endif
|
||||
|
||||
if (localName == nil) return [NSArray array];
|
||||
|
||||
// We need to figure out what the prefix is for this URI.
|
||||
// Then we search for elements that are named prefix:localName OR (named localName AND have the given URI).
|
||||
|
||||
NSString *prefix = [self _recursiveResolvePrefixForURI:uri atNode:(xmlNodePtr)genericPtr];
|
||||
if (prefix)
|
||||
{
|
||||
NSString *name = [NSString stringWithFormat:@"%@:%@", prefix, localName];
|
||||
|
||||
return [self _elementsForName:name localName:localName prefix:prefix uri:uri];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSString *prefix;
|
||||
NSString *realLocalName;
|
||||
|
||||
[DDXMLNode getPrefix:&prefix localName:&realLocalName forName:localName];
|
||||
|
||||
return [self _elementsForName:localName localName:realLocalName prefix:prefix uri:uri];
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark Attributes
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (BOOL)_hasAttributeWithName:(NSString *)name
|
||||
{
|
||||
// This is a private/internal method
|
||||
|
||||
xmlAttrPtr attr = ((xmlNodePtr)genericPtr)->properties;
|
||||
if (attr)
|
||||
{
|
||||
const xmlChar *xmlName = [name xmlChar];
|
||||
do
|
||||
{
|
||||
if (xmlStrEqual(attr->name, xmlName))
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
attr = attr->next;
|
||||
|
||||
} while (attr);
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)_removeAttributeForName:(NSString *)name
|
||||
{
|
||||
// This is a private/internal method
|
||||
|
||||
xmlAttrPtr attr = ((xmlNodePtr)genericPtr)->properties;
|
||||
if (attr)
|
||||
{
|
||||
const xmlChar *xmlName = [name xmlChar];
|
||||
do
|
||||
{
|
||||
if (xmlStrEqual(attr->name, xmlName))
|
||||
{
|
||||
[DDXMLNode removeAttribute:attr];
|
||||
return;
|
||||
}
|
||||
attr = attr->next;
|
||||
|
||||
} while(attr);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)addAttribute:(DDXMLNode *)attribute
|
||||
{
|
||||
#if DDXML_DEBUG_MEMORY_ISSUES
|
||||
DDXMLNotZombieAssert();
|
||||
#endif
|
||||
|
||||
// NSXML version uses this same assertion
|
||||
DDXMLAssert([attribute _hasParent] == NO, @"Cannot add an attribute with a parent; detach or copy first");
|
||||
DDXMLAssert(IsXmlAttrPtr(attribute->genericPtr), @"Not an attribute");
|
||||
|
||||
[self _removeAttributeForName:[attribute name]];
|
||||
|
||||
// xmlNodePtr xmlAddChild(xmlNodePtr parent, xmlNodePtr cur)
|
||||
// Add a new node to @parent, at the end of the child (or property) list merging
|
||||
// adjacent TEXT nodes (in which case @cur is freed). If the new node is ATTRIBUTE, it is added
|
||||
// into properties instead of children. If there is an attribute with equal name, it is first destroyed.
|
||||
|
||||
xmlAddChild((xmlNodePtr)genericPtr, (xmlNodePtr)attribute->genericPtr);
|
||||
|
||||
// The attribute is now part of the xml tree heirarchy
|
||||
attribute->owner = self;
|
||||
}
|
||||
|
||||
- (void)removeAttributeForName:(NSString *)name
|
||||
{
|
||||
#if DDXML_DEBUG_MEMORY_ISSUES
|
||||
DDXMLNotZombieAssert();
|
||||
#endif
|
||||
|
||||
[self _removeAttributeForName:name];
|
||||
}
|
||||
|
||||
- (NSArray *)attributes
|
||||
{
|
||||
#if DDXML_DEBUG_MEMORY_ISSUES
|
||||
DDXMLNotZombieAssert();
|
||||
#endif
|
||||
|
||||
NSMutableArray *result = [NSMutableArray array];
|
||||
|
||||
xmlAttrPtr attr = ((xmlNodePtr)genericPtr)->properties;
|
||||
while (attr != NULL)
|
||||
{
|
||||
[result addObject:[DDXMLAttributeNode nodeWithAttrPrimitive:attr owner:self]];
|
||||
|
||||
attr = attr->next;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (DDXMLNode *)attributeForName:(NSString *)name
|
||||
{
|
||||
#if DDXML_DEBUG_MEMORY_ISSUES
|
||||
DDXMLNotZombieAssert();
|
||||
#endif
|
||||
|
||||
xmlAttrPtr attr = ((xmlNodePtr)genericPtr)->properties;
|
||||
if (attr)
|
||||
{
|
||||
const xmlChar *xmlName = [name xmlChar];
|
||||
do
|
||||
{
|
||||
if (attr->ns && attr->ns->prefix)
|
||||
{
|
||||
// If the attribute name was originally something like "xml:quack",
|
||||
// then attr->name is "quack" and attr->ns->prefix is "xml".
|
||||
//
|
||||
// So if the user is searching for "xml:quack" we need to take the prefix into account.
|
||||
// Note that "xml:quack" is what would be printed if we output the attribute.
|
||||
|
||||
if (xmlStrQEqual(attr->ns->prefix, attr->name, xmlName))
|
||||
{
|
||||
return [DDXMLAttributeNode nodeWithAttrPrimitive:attr owner:self];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (xmlStrEqual(attr->name, xmlName))
|
||||
{
|
||||
return [DDXMLAttributeNode nodeWithAttrPrimitive:attr owner:self];
|
||||
}
|
||||
}
|
||||
|
||||
attr = attr->next;
|
||||
|
||||
} while (attr);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the list of attributes for the element.
|
||||
* Any previously set attributes are removed.
|
||||
**/
|
||||
- (void)setAttributes:(NSArray *)attributes
|
||||
{
|
||||
#if DDXML_DEBUG_MEMORY_ISSUES
|
||||
DDXMLNotZombieAssert();
|
||||
#endif
|
||||
|
||||
[DDXMLNode removeAllAttributesFromNode:(xmlNodePtr)genericPtr];
|
||||
|
||||
NSUInteger i;
|
||||
for (i = 0; i < [attributes count]; i++)
|
||||
{
|
||||
DDXMLNode *attribute = [attributes objectAtIndex:i];
|
||||
[self addAttribute:attribute];
|
||||
|
||||
// Note: The addAttributes method properly sets the freeOnDealloc ivar.
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark Namespaces
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)_removeNamespaceForPrefix:(NSString *)name
|
||||
{
|
||||
xmlNodePtr node = (xmlNodePtr)genericPtr;
|
||||
|
||||
// If name is nil or the empty string, the user is wishing to remove the default namespace
|
||||
const xmlChar *xmlName = [name length] > 0 ? [name xmlChar] : NULL;
|
||||
|
||||
xmlNsPtr ns = node->nsDef;
|
||||
while (ns != NULL)
|
||||
{
|
||||
if (xmlStrEqual(ns->prefix, xmlName))
|
||||
{
|
||||
[DDXMLNode removeNamespace:ns fromNode:node];
|
||||
break;
|
||||
}
|
||||
ns = ns->next;
|
||||
}
|
||||
|
||||
// Note: The removeNamespace method properly handles the situation where the namespace is the default namespace
|
||||
}
|
||||
|
||||
- (void)_addNamespace:(DDXMLNode *)namespace
|
||||
{
|
||||
// NSXML version uses this same assertion
|
||||
DDXMLAssert([namespace _hasParent] == NO, @"Cannot add a namespace with a parent; detach or copy first");
|
||||
DDXMLAssert(IsXmlNsPtr(namespace->genericPtr), @"Not a namespace");
|
||||
|
||||
xmlNodePtr node = (xmlNodePtr)genericPtr;
|
||||
xmlNsPtr ns = (xmlNsPtr)namespace->genericPtr;
|
||||
|
||||
// Beware: [namespace prefix] does NOT return what you might expect. Use [namespace name] instead.
|
||||
|
||||
NSString *namespaceName = [namespace name];
|
||||
|
||||
[self _removeNamespaceForPrefix:namespaceName];
|
||||
|
||||
xmlNsPtr currentNs = node->nsDef;
|
||||
if (currentNs == NULL)
|
||||
{
|
||||
node->nsDef = ns;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (currentNs->next != NULL)
|
||||
{
|
||||
currentNs = currentNs->next;
|
||||
}
|
||||
|
||||
currentNs->next = ns;
|
||||
}
|
||||
|
||||
// The namespace is now part of the xml tree heirarchy
|
||||
namespace->owner = self;
|
||||
|
||||
if ([namespace isKindOfClass:[DDXMLNamespaceNode class]])
|
||||
{
|
||||
DDXMLNamespaceNode *ddNamespace = (DDXMLNamespaceNode *)namespace;
|
||||
|
||||
// The xmlNs structure doesn't contain a reference to the parent, so we manage our own reference
|
||||
[ddNamespace _setNsParentPtr:node];
|
||||
}
|
||||
|
||||
// Did we just add a default namespace
|
||||
if ([namespaceName isEqualToString:@""])
|
||||
{
|
||||
node->ns = ns;
|
||||
|
||||
// Note: The removeNamespaceForPrefix method above properly handled removing any previous default namespace
|
||||
}
|
||||
}
|
||||
|
||||
- (void)addNamespace:(DDXMLNode *)namespace
|
||||
{
|
||||
#if DDXML_DEBUG_MEMORY_ISSUES
|
||||
DDXMLNotZombieAssert();
|
||||
#endif
|
||||
|
||||
[self _addNamespace:namespace];
|
||||
}
|
||||
|
||||
- (void)removeNamespaceForPrefix:(NSString *)name
|
||||
{
|
||||
#if DDXML_DEBUG_MEMORY_ISSUES
|
||||
DDXMLNotZombieAssert();
|
||||
#endif
|
||||
|
||||
[self _removeNamespaceForPrefix:name];
|
||||
}
|
||||
|
||||
- (NSArray *)namespaces
|
||||
{
|
||||
#if DDXML_DEBUG_MEMORY_ISSUES
|
||||
DDXMLNotZombieAssert();
|
||||
#endif
|
||||
|
||||
NSMutableArray *result = [NSMutableArray array];
|
||||
|
||||
xmlNsPtr ns = ((xmlNodePtr)genericPtr)->nsDef;
|
||||
while (ns != NULL)
|
||||
{
|
||||
[result addObject:[DDXMLNamespaceNode nodeWithNsPrimitive:ns nsParent:(xmlNodePtr)genericPtr owner:self]];
|
||||
|
||||
ns = ns->next;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (DDXMLNode *)namespaceForPrefix:(NSString *)prefix
|
||||
{
|
||||
#if DDXML_DEBUG_MEMORY_ISSUES
|
||||
DDXMLNotZombieAssert();
|
||||
#endif
|
||||
|
||||
// If the prefix is nil or the empty string, the user is requesting the default namespace
|
||||
|
||||
if ([prefix length] == 0)
|
||||
{
|
||||
// Requesting the default namespace
|
||||
xmlNsPtr ns = ((xmlNodePtr)genericPtr)->ns;
|
||||
if (ns != NULL)
|
||||
{
|
||||
return [DDXMLNamespaceNode nodeWithNsPrimitive:ns nsParent:(xmlNodePtr)genericPtr owner:self];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
xmlNsPtr ns = ((xmlNodePtr)genericPtr)->nsDef;
|
||||
if (ns)
|
||||
{
|
||||
const xmlChar *xmlPrefix = [prefix xmlChar];
|
||||
do
|
||||
{
|
||||
if (xmlStrEqual(ns->prefix, xmlPrefix))
|
||||
{
|
||||
return [DDXMLNamespaceNode nodeWithNsPrimitive:ns nsParent:(xmlNodePtr)genericPtr owner:self];
|
||||
}
|
||||
ns = ns->next;
|
||||
|
||||
} while (ns);
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)setNamespaces:(NSArray *)namespaces
|
||||
{
|
||||
#if DDXML_DEBUG_MEMORY_ISSUES
|
||||
DDXMLNotZombieAssert();
|
||||
#endif
|
||||
|
||||
[DDXMLNode removeAllNamespacesFromNode:(xmlNodePtr)genericPtr];
|
||||
|
||||
NSUInteger i;
|
||||
for (i = 0; i < [namespaces count]; i++)
|
||||
{
|
||||
DDXMLNode *namespace = [namespaces objectAtIndex:i];
|
||||
[self _addNamespace:namespace];
|
||||
|
||||
// Note: The addNamespace method properly sets the freeOnDealloc ivar.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively searches the given node for the given namespace
|
||||
**/
|
||||
- (DDXMLNode *)_recursiveResolveNamespaceForPrefix:(NSString *)prefix atNode:(xmlNodePtr)nodePtr
|
||||
{
|
||||
// This is a private/internal method
|
||||
|
||||
if (nodePtr == NULL) return nil;
|
||||
|
||||
xmlNsPtr ns = nodePtr->nsDef;
|
||||
if (ns)
|
||||
{
|
||||
const xmlChar *xmlPrefix = [prefix xmlChar];
|
||||
do
|
||||
{
|
||||
if (xmlStrEqual(ns->prefix, xmlPrefix))
|
||||
{
|
||||
return [DDXMLNamespaceNode nodeWithNsPrimitive:ns nsParent:nodePtr owner:self];
|
||||
}
|
||||
ns = ns->next;
|
||||
|
||||
} while(ns);
|
||||
}
|
||||
|
||||
return [self _recursiveResolveNamespaceForPrefix:prefix atNode:nodePtr->parent];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the namespace node with the prefix matching the given qualified name.
|
||||
* Eg: You pass it "a:dog", it returns the namespace (defined in this node or parent nodes) that has the "a" prefix.
|
||||
**/
|
||||
- (DDXMLNode *)resolveNamespaceForName:(NSString *)name
|
||||
{
|
||||
#if DDXML_DEBUG_MEMORY_ISSUES
|
||||
DDXMLNotZombieAssert();
|
||||
#endif
|
||||
|
||||
// If the user passes nil or an empty string for name, they're looking for the default namespace.
|
||||
if ([name length] == 0)
|
||||
{
|
||||
return [self _recursiveResolveNamespaceForPrefix:nil atNode:(xmlNodePtr)genericPtr];
|
||||
}
|
||||
|
||||
NSString *prefix = [[self class] prefixForName:name];
|
||||
|
||||
if ([prefix length] > 0)
|
||||
{
|
||||
// Unfortunately we can't use xmlSearchNs because it returns an xmlNsPtr.
|
||||
// This gives us mostly what we want, except we also need to know the nsParent.
|
||||
// So we do the recursive search ourselves.
|
||||
|
||||
return [self _recursiveResolveNamespaceForPrefix:prefix atNode:(xmlNodePtr)genericPtr];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively searches the given node for a namespace with the given URI, and a set prefix.
|
||||
**/
|
||||
- (NSString *)_recursiveResolvePrefixForURI:(NSString *)uri atNode:(xmlNodePtr)nodePtr
|
||||
{
|
||||
// This is a private/internal method
|
||||
|
||||
if (nodePtr == NULL) return nil;
|
||||
|
||||
xmlNsPtr ns = nodePtr->nsDef;
|
||||
if (ns)
|
||||
{
|
||||
const xmlChar *xmlUri = [uri xmlChar];
|
||||
do
|
||||
{
|
||||
if (xmlStrEqual(ns->href, xmlUri))
|
||||
{
|
||||
if (ns->prefix != NULL)
|
||||
{
|
||||
return [NSString stringWithUTF8String:((const char *)ns->prefix)];
|
||||
}
|
||||
}
|
||||
ns = ns->next;
|
||||
|
||||
} while (ns);
|
||||
}
|
||||
|
||||
return [self _recursiveResolvePrefixForURI:uri atNode:nodePtr->parent];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the prefix associated with the specified URI.
|
||||
* Returns a string that is the matching prefix or nil if it finds no matching prefix.
|
||||
**/
|
||||
- (NSString *)resolvePrefixForNamespaceURI:(NSString *)namespaceURI
|
||||
{
|
||||
#if DDXML_DEBUG_MEMORY_ISSUES
|
||||
DDXMLNotZombieAssert();
|
||||
#endif
|
||||
|
||||
// We can't use xmlSearchNsByHref because it will return xmlNsPtr's with NULL prefixes.
|
||||
// We're looking for a definitive prefix for the given URI.
|
||||
|
||||
return [self _recursiveResolvePrefixForURI:namespaceURI atNode:(xmlNodePtr)genericPtr];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark Children
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)addChild:(DDXMLNode *)child
|
||||
{
|
||||
#if DDXML_DEBUG_MEMORY_ISSUES
|
||||
DDXMLNotZombieAssert();
|
||||
#endif
|
||||
|
||||
// NSXML version uses these same assertions
|
||||
DDXMLAssert([child _hasParent] == NO, @"Cannot add a child that has a parent; detach or copy first");
|
||||
DDXMLAssert(IsXmlNodePtr(child->genericPtr),
|
||||
@"Elements can only have text, elements, processing instructions, and comments as children");
|
||||
|
||||
xmlAddChild((xmlNodePtr)genericPtr, (xmlNodePtr)child->genericPtr);
|
||||
|
||||
// The node is now part of the xml tree heirarchy
|
||||
child->owner = self;
|
||||
}
|
||||
|
||||
- (void)insertChild:(DDXMLNode *)child atIndex:(NSUInteger)index
|
||||
{
|
||||
#if DDXML_DEBUG_MEMORY_ISSUES
|
||||
DDXMLNotZombieAssert();
|
||||
#endif
|
||||
|
||||
// NSXML version uses these same assertions
|
||||
DDXMLAssert([child _hasParent] == NO, @"Cannot add a child that has a parent; detach or copy first");
|
||||
DDXMLAssert(IsXmlNodePtr(child->genericPtr),
|
||||
@"Elements can only have text, elements, processing instructions, and comments as children");
|
||||
|
||||
NSUInteger i = 0;
|
||||
|
||||
xmlNodePtr childNodePtr = ((xmlNodePtr)genericPtr)->children;
|
||||
while (childNodePtr != NULL)
|
||||
{
|
||||
// Ignore all but element, comment, text, or processing instruction nodes
|
||||
if (IsXmlNodePtr(childNodePtr))
|
||||
{
|
||||
if (i == index)
|
||||
{
|
||||
xmlAddPrevSibling(childNodePtr, (xmlNodePtr)child->genericPtr);
|
||||
|
||||
child->owner = self;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
childNodePtr = childNodePtr->next;
|
||||
}
|
||||
|
||||
if (i == index)
|
||||
{
|
||||
xmlAddChild((xmlNodePtr)genericPtr, (xmlNodePtr)child->genericPtr);
|
||||
|
||||
child->owner = self;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// NSXML version uses this same assertion
|
||||
DDXMLAssert(NO, @"index (%u) beyond bounds (%u)", (unsigned)index, (unsigned)++i);
|
||||
}
|
||||
|
||||
- (void)removeChildAtIndex:(NSUInteger)index
|
||||
{
|
||||
#if DDXML_DEBUG_MEMORY_ISSUES
|
||||
DDXMLNotZombieAssert();
|
||||
#endif
|
||||
|
||||
NSUInteger i = 0;
|
||||
|
||||
xmlNodePtr child = ((xmlNodePtr)genericPtr)->children;
|
||||
while (child != NULL)
|
||||
{
|
||||
// Ignore all but element, comment, text, or processing instruction nodes
|
||||
if (IsXmlNodePtr(child))
|
||||
{
|
||||
if (i == index)
|
||||
{
|
||||
[DDXMLNode removeChild:child];
|
||||
return;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
child = child->next;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setChildren:(NSArray *)children
|
||||
{
|
||||
#if DDXML_DEBUG_MEMORY_ISSUES
|
||||
DDXMLNotZombieAssert();
|
||||
#endif
|
||||
|
||||
[DDXMLNode removeAllChildrenFromNode:(xmlNodePtr)genericPtr];
|
||||
|
||||
NSUInteger i;
|
||||
for (i = 0; i < [children count]; i++)
|
||||
{
|
||||
DDXMLNode *child = [children objectAtIndex:i];
|
||||
[self addChild:child];
|
||||
|
||||
// Note: The addChild method properly sets the freeOnDealloc ivar.
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
Generated
+167
@@ -0,0 +1,167 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#if DDXML_LIBXML_MODULE_ENABLED
|
||||
#if TARGET_OS_IOS && TARGET_OS_EMBEDDED
|
||||
@import libxml;
|
||||
#elif TARGET_IPHONE_SIMULATOR
|
||||
@import libxmlSimu;
|
||||
#elif TARGET_OS_MAC
|
||||
@import libxmlMac;
|
||||
#endif
|
||||
#else
|
||||
#import <libxml/tree.h>
|
||||
#endif
|
||||
|
||||
@class DDXMLDocument;
|
||||
|
||||
/**
|
||||
* Welcome to KissXML.
|
||||
*
|
||||
* The project page has documentation if you have questions.
|
||||
* https://github.com/robbiehanson/KissXML
|
||||
*
|
||||
* If you're new to the project you may wish to read the "Getting Started" wiki.
|
||||
* https://github.com/robbiehanson/KissXML/wiki/GettingStarted
|
||||
*
|
||||
* KissXML provides a drop-in replacement for Apple's NSXML class cluster.
|
||||
* The goal is to get the exact same behavior as the NSXML classes.
|
||||
*
|
||||
* For API Reference, see Apple's excellent documentation,
|
||||
* either via Xcode's Mac OS X documentation, or via the web:
|
||||
*
|
||||
* https://github.com/robbiehanson/KissXML/wiki/Reference
|
||||
**/
|
||||
|
||||
enum {
|
||||
DDXMLInvalidKind = 0,
|
||||
DDXMLDocumentKind = XML_DOCUMENT_NODE,
|
||||
DDXMLElementKind = XML_ELEMENT_NODE,
|
||||
DDXMLAttributeKind = XML_ATTRIBUTE_NODE,
|
||||
DDXMLNamespaceKind = XML_NAMESPACE_DECL,
|
||||
DDXMLProcessingInstructionKind = XML_PI_NODE,
|
||||
DDXMLCommentKind = XML_COMMENT_NODE,
|
||||
DDXMLTextKind = XML_TEXT_NODE,
|
||||
DDXMLDTDKind = XML_DTD_NODE,
|
||||
DDXMLEntityDeclarationKind = XML_ENTITY_DECL,
|
||||
DDXMLAttributeDeclarationKind = XML_ATTRIBUTE_DECL,
|
||||
DDXMLElementDeclarationKind = XML_ELEMENT_DECL,
|
||||
DDXMLNotationDeclarationKind = XML_NOTATION_NODE
|
||||
};
|
||||
typedef NSUInteger DDXMLNodeKind;
|
||||
|
||||
enum {
|
||||
DDXMLNodeOptionsNone = 0,
|
||||
DDXMLNodeExpandEmptyElement = 1 << 1,
|
||||
DDXMLNodeCompactEmptyElement = 1 << 2,
|
||||
DDXMLNodePrettyPrint = 1 << 17,
|
||||
};
|
||||
|
||||
|
||||
//extern struct _xmlKind;
|
||||
|
||||
|
||||
@interface DDXMLNode : NSObject <NSCopying>
|
||||
{
|
||||
// Every DDXML object is simply a wrapper around an underlying libxml node
|
||||
struct _xmlKind *genericPtr;
|
||||
|
||||
// Every libxml node resides somewhere within an xml tree heirarchy.
|
||||
// We cannot free the tree heirarchy until all referencing nodes have been released.
|
||||
// So all nodes retain a reference to the node that created them,
|
||||
// and when the last reference is released the tree gets freed.
|
||||
DDXMLNode *owner;
|
||||
}
|
||||
|
||||
//- (id)initWithKind:(DDXMLNodeKind)kind;
|
||||
|
||||
//- (id)initWithKind:(DDXMLNodeKind)kind options:(NSUInteger)options;
|
||||
|
||||
//+ (id)document;
|
||||
|
||||
//+ (id)documentWithRootElement:(DDXMLElement *)element;
|
||||
|
||||
+ (id)elementWithName:(NSString *)name;
|
||||
|
||||
+ (id)elementWithName:(NSString *)name URI:(NSString *)URI;
|
||||
|
||||
+ (id)elementWithName:(NSString *)name stringValue:(NSString *)string;
|
||||
|
||||
+ (id)elementWithName:(NSString *)name children:(NSArray *)children attributes:(NSArray *)attributes;
|
||||
|
||||
+ (id)attributeWithName:(NSString *)name stringValue:(NSString *)stringValue;
|
||||
|
||||
+ (id)attributeWithName:(NSString *)name URI:(NSString *)URI stringValue:(NSString *)stringValue;
|
||||
|
||||
+ (id)namespaceWithName:(NSString *)name stringValue:(NSString *)stringValue;
|
||||
|
||||
+ (id)processingInstructionWithName:(NSString *)name stringValue:(NSString *)stringValue;
|
||||
|
||||
+ (id)commentWithStringValue:(NSString *)stringValue;
|
||||
|
||||
+ (id)textWithStringValue:(NSString *)stringValue;
|
||||
|
||||
//+ (id)DTDNodeWithXMLString:(NSString *)string;
|
||||
|
||||
#pragma mark --- Properties ---
|
||||
|
||||
- (DDXMLNodeKind)kind;
|
||||
|
||||
- (void)setName:(NSString *)name;
|
||||
- (NSString *)name;
|
||||
|
||||
//- (void)setObjectValue:(id)value;
|
||||
//- (id)objectValue;
|
||||
|
||||
- (void)setStringValue:(NSString *)string;
|
||||
//- (void)setStringValue:(NSString *)string resolvingEntities:(BOOL)resolve;
|
||||
- (NSString *)stringValue;
|
||||
|
||||
#pragma mark --- Tree Navigation ---
|
||||
|
||||
- (NSUInteger)index;
|
||||
|
||||
- (NSUInteger)level;
|
||||
|
||||
- (DDXMLDocument *)rootDocument;
|
||||
|
||||
- (DDXMLNode *)parent;
|
||||
- (NSUInteger)childCount;
|
||||
- (NSArray *)children;
|
||||
- (DDXMLNode *)childAtIndex:(NSUInteger)index;
|
||||
|
||||
- (DDXMLNode *)previousSibling;
|
||||
- (DDXMLNode *)nextSibling;
|
||||
|
||||
- (DDXMLNode *)previousNode;
|
||||
- (DDXMLNode *)nextNode;
|
||||
|
||||
- (void)detach;
|
||||
|
||||
- (NSString *)XPath;
|
||||
|
||||
#pragma mark --- QNames ---
|
||||
|
||||
- (NSString *)localName;
|
||||
- (NSString *)prefix;
|
||||
|
||||
- (void)setURI:(NSString *)URI;
|
||||
- (NSString *)URI;
|
||||
|
||||
+ (NSString *)localNameForName:(NSString *)name;
|
||||
+ (NSString *)prefixForName:(NSString *)name;
|
||||
//+ (DDXMLNode *)predefinedNamespaceForPrefix:(NSString *)name;
|
||||
|
||||
#pragma mark --- Output ---
|
||||
|
||||
- (NSString *)description;
|
||||
- (NSString *)XMLString;
|
||||
- (NSString *)XMLStringWithOptions:(NSUInteger)options;
|
||||
//- (NSString *)canonicalXMLStringPreservingComments:(BOOL)comments;
|
||||
|
||||
#pragma mark --- XPath/XQuery ---
|
||||
|
||||
- (NSArray *)nodesForXPath:(NSString *)xpath error:(NSError **)error;
|
||||
//- (NSArray *)objectsForXQuery:(NSString *)xquery constants:(NSDictionary *)constants error:(NSError **)error;
|
||||
//- (NSArray *)objectsForXQuery:(NSString *)xquery error:(NSError **)error;
|
||||
|
||||
@end
|
||||
Generated
+2905
File diff suppressed because it is too large.
Load diff
+229
@@ -0,0 +1,229 @@
|
||||
#import "DDXML.h"
|
||||
|
||||
|
||||
// We can't rely solely on NSAssert, because many developers disable them for release builds.
|
||||
// Our API contract requires us to keep these assertions intact.
|
||||
#define DDXMLAssert(condition, desc, ...) \
|
||||
do{ \
|
||||
if(!(condition)) { \
|
||||
[[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd \
|
||||
object:self \
|
||||
file:[NSString stringWithUTF8String:__FILE__] \
|
||||
lineNumber:__LINE__ \
|
||||
description:(desc), ##__VA_ARGS__]; \
|
||||
} \
|
||||
}while(NO)
|
||||
|
||||
|
||||
// Create assertion to ensure xml node is not a zombie.
|
||||
#if DDXML_DEBUG_MEMORY_ISSUES
|
||||
#define DDXMLNotZombieAssert() \
|
||||
do{ \
|
||||
if(DDXMLIsZombie(genericPtr, self)) { \
|
||||
NSString *desc = @"XML node is a zombie - It's parent structure has been freed!"; \
|
||||
[[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd \
|
||||
object:self \
|
||||
file:[NSString stringWithUTF8String:__FILE__] \
|
||||
lineNumber:__LINE__ \
|
||||
description:desc]; \
|
||||
} \
|
||||
}while(NO)
|
||||
#endif
|
||||
|
||||
#define DDLastErrorKey @"DDXML:LastError"
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* DDXMLNode can represent several underlying types, such as xmlNodePtr, xmlDocPtr, xmlAttrPtr, xmlNsPtr, etc.
|
||||
* All of these are pointers to structures, and all of those structures start with a pointer, and a type.
|
||||
* The xmlKind struct is used as a generic structure, and a stepping stone.
|
||||
* We use it to check the type of a structure, and then perform the appropriate cast.
|
||||
*
|
||||
* For example:
|
||||
* if(genericPtr->type == XML_ATTRIBUTE_NODE)
|
||||
* {
|
||||
* xmlAttrPtr attr = (xmlAttrPtr)genericPtr;
|
||||
* // Do something with attr
|
||||
* }
|
||||
**/
|
||||
struct _xmlKind {
|
||||
void * ignore;
|
||||
xmlElementType type;
|
||||
};
|
||||
typedef struct _xmlKind *xmlKindPtr;
|
||||
|
||||
/**
|
||||
* Most xml types all start with this standard structure. In fact, all do except the xmlNsPtr.
|
||||
* We will occasionally take advantage of this to simplify code when the code wouldn't vary from type to type.
|
||||
* Obviously, you cannnot cast a xmlNsPtr to a xmlStdPtr.
|
||||
**/
|
||||
struct _xmlStd {
|
||||
void * _private;
|
||||
xmlElementType type;
|
||||
const xmlChar *name;
|
||||
struct _xmlNode *children;
|
||||
struct _xmlNode *last;
|
||||
struct _xmlNode *parent;
|
||||
struct _xmlStd *next;
|
||||
struct _xmlStd *prev;
|
||||
struct _xmlDoc *doc;
|
||||
};
|
||||
typedef struct _xmlStd *xmlStdPtr;
|
||||
|
||||
|
||||
NS_INLINE BOOL IsXmlAttrPtr(void *kindPtr)
|
||||
{
|
||||
return ((xmlKindPtr)kindPtr)->type == XML_ATTRIBUTE_NODE;
|
||||
}
|
||||
|
||||
NS_INLINE BOOL IsXmlNodePtr(void *kindPtr)
|
||||
{
|
||||
switch (((xmlKindPtr)kindPtr)->type)
|
||||
{
|
||||
case XML_ELEMENT_NODE :
|
||||
case XML_PI_NODE :
|
||||
case XML_COMMENT_NODE :
|
||||
case XML_TEXT_NODE :
|
||||
case XML_CDATA_SECTION_NODE : return YES;
|
||||
default : return NO;
|
||||
}
|
||||
}
|
||||
|
||||
NS_INLINE BOOL IsXmlDocPtr(void *kindPtr)
|
||||
{
|
||||
return ((xmlKindPtr)kindPtr)->type == XML_DOCUMENT_NODE;
|
||||
}
|
||||
|
||||
NS_INLINE BOOL IsXmlDtdPtr(void *kindPtr)
|
||||
{
|
||||
return ((xmlKindPtr)kindPtr)->type == XML_DTD_NODE;
|
||||
}
|
||||
|
||||
NS_INLINE BOOL IsXmlNsPtr(void *kindPtr)
|
||||
{
|
||||
return ((xmlKindPtr)kindPtr)->type == XML_NAMESPACE_DECL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark -
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@interface DDXMLNamespaceNode : DDXMLNode
|
||||
{
|
||||
// The xmlNsPtr type doesn't store a reference to it's parent.
|
||||
// This is here to fix the problem, and make this class more compatible with the NSXML classes.
|
||||
xmlNodePtr nsParentPtr;
|
||||
}
|
||||
|
||||
+ (id)nodeWithNsPrimitive:(xmlNsPtr)ns nsParent:(xmlNodePtr)parent owner:(DDXMLNode *)owner;
|
||||
- (id)initWithNsPrimitive:(xmlNsPtr)ns nsParent:(xmlNodePtr)parent owner:(DDXMLNode *)owner;
|
||||
|
||||
- (xmlNodePtr)_nsParentPtr;
|
||||
- (void)_setNsParentPtr:(xmlNodePtr)parentPtr;
|
||||
|
||||
// Overrides several methods in DDXMLNode
|
||||
|
||||
@end
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark -
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@interface DDXMLAttributeNode : DDXMLNode
|
||||
{
|
||||
// The xmlAttrPtr type doesn't allow for ownership of a namespace.
|
||||
//
|
||||
// In other types, such as xmlNodePtr:
|
||||
// - nsDef stores namespaces that are owned by the node (have been alloced by the node).
|
||||
// - ns is simply a pointer to the default namespace of the node, which may or may not reside in its own nsDef list.
|
||||
//
|
||||
// The xmlAttrPtr only has a ns, it doesn't have a nsDef list.
|
||||
// Which completely makes sense really, since namespaces have to be defined elsewhere.
|
||||
//
|
||||
// This is here to maintain compatibility with the NSXML classes,
|
||||
// where one can assign a namespace to an attribute independently.
|
||||
xmlNsPtr attrNsPtr;
|
||||
}
|
||||
|
||||
+ (id)nodeWithAttrPrimitive:(xmlAttrPtr)attr owner:(DDXMLNode *)owner;
|
||||
- (id)initWithAttrPrimitive:(xmlAttrPtr)attr owner:(DDXMLNode *)owner;
|
||||
|
||||
// Overrides several methods in DDXMLNode
|
||||
|
||||
@end
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark -
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@interface DDXMLInvalidNode : DDXMLNode
|
||||
{
|
||||
}
|
||||
|
||||
// Overrides several methods in DDXMLNode
|
||||
|
||||
@end
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark -
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@interface DDXMLNode (PrivateAPI)
|
||||
|
||||
+ (id)nodeWithUnknownPrimitive:(xmlKindPtr)kindPtr owner:(DDXMLNode *)owner;
|
||||
|
||||
+ (id)nodeWithPrimitive:(xmlKindPtr)kindPtr owner:(DDXMLNode *)owner;
|
||||
- (id)initWithPrimitive:(xmlKindPtr)kindPtr owner:(DDXMLNode *)owner;
|
||||
|
||||
- (BOOL)_hasParent;
|
||||
|
||||
+ (void)getHasPrefix:(BOOL *)hasPrefixPtr localName:(NSString **)localNamePtr forName:(NSString *)name;
|
||||
+ (void)getPrefix:(NSString **)prefixPtr localName:(NSString **)localNamePtr forName:(NSString *)name;
|
||||
|
||||
+ (void)recursiveStripDocPointersFromNode:(xmlNodePtr)node;
|
||||
|
||||
+ (void)detachNamespace:(xmlNsPtr)ns fromNode:(xmlNodePtr)node;
|
||||
+ (void)removeNamespace:(xmlNsPtr)ns fromNode:(xmlNodePtr)node;
|
||||
+ (void)removeAllNamespacesFromNode:(xmlNodePtr)node;
|
||||
|
||||
+ (void)detachAttribute:(xmlAttrPtr)attr andClean:(BOOL)clean;
|
||||
+ (void)detachAttribute:(xmlAttrPtr)attr;
|
||||
+ (void)removeAttribute:(xmlAttrPtr)attr;
|
||||
+ (void)removeAllAttributesFromNode:(xmlNodePtr)node;
|
||||
|
||||
+ (void)detachChild:(xmlNodePtr)child andClean:(BOOL)clean andFixNamespaces:(BOOL)fixNamespaces;
|
||||
+ (void)detachChild:(xmlNodePtr)child;
|
||||
+ (void)removeChild:(xmlNodePtr)child;
|
||||
+ (void)removeAllChildrenFromNode:(xmlNodePtr)node;
|
||||
|
||||
BOOL DDXMLIsZombie(void *xmlPtr, DDXMLNode *wrapper);
|
||||
|
||||
+ (NSError *)lastError;
|
||||
|
||||
@end
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark -
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@interface DDXMLElement (PrivateAPI)
|
||||
|
||||
+ (id)nodeWithElementPrimitive:(xmlNodePtr)node owner:(DDXMLNode *)owner;
|
||||
- (id)initWithElementPrimitive:(xmlNodePtr)node owner:(DDXMLNode *)owner;
|
||||
|
||||
- (DDXMLNode *)_recursiveResolveNamespaceForPrefix:(NSString *)prefix atNode:(xmlNodePtr)nodePtr;
|
||||
- (NSString *)_recursiveResolvePrefixForURI:(NSString *)uri atNode:(xmlNodePtr)nodePtr;
|
||||
|
||||
@end
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark -
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@interface DDXMLDocument (PrivateAPI)
|
||||
|
||||
+ (id)nodeWithDocPrimitive:(xmlDocPtr)doc owner:(DDXMLNode *)owner;
|
||||
- (id)initWithDocPrimitive:(xmlDocPtr)doc owner:(DDXMLNode *)owner;
|
||||
|
||||
@end
|
||||
Generated
+8
@@ -0,0 +1,8 @@
|
||||
Copyright (c) 2012, Robbie Hanson
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
Generated
+34
@@ -0,0 +1,34 @@
|
||||
# [KissXML](https://github.com/robbiehanson/KissXML)
|
||||
|
||||
[](https://travis-ci.org/robbiehanson/KissXML)
|
||||
[](http://cocoapods.org/pods/KissXML)
|
||||
[](http://cocoapods.org/pods/KissXML)
|
||||
[](http://cocoapods.org/pods/KissXML)
|
||||
|
||||
KissXML provides a drop-in replacement for Apple's NSXML class culster in environments without NSXML (e.g. iOS).
|
||||
|
||||
It is implemented atop the defacto libxml2 C library, which comes pre-installed on Mac & iOS.
|
||||
But it shields you from all the nasty low-level C pointers and malloc's, and provides an easy-to-use Objective-C library.
|
||||
|
||||
It is designed for speed and reliability, so it's read-access thread-safe and will "just-work".
|
||||
That is, KissXML provides an API that follows "what-you-would-expect" rules from an Objective-C library.
|
||||
So feel free to do things like parallel processing of an xml document using blocks.
|
||||
It will "just work" so you can get back to designing the rest of your app.
|
||||
|
||||
KissXML is a mature library used in thousands of products. It's also used in other libraries, such as [XMPPFramework](http://code.google.com/p/xmppframework/) (an objective-c library for real-time xml streaming). It's even used in hospital applications.
|
||||
|
||||
KissXML was inspired by the TouchXML project, but was created to add full support for generating XML as well as supporting the entire NSXML API.
|
||||
|
||||
**[Get started using KissXML](https://github.com/robbiehanson/KissXML/wiki/GettingStarted)**<br/>
|
||||
**[Learn more about KissXML](https://github.com/robbiehanson/KissXML/wiki)**<br/>
|
||||
|
||||
<br/>
|
||||
Can't find the answer to your question in any of the [wiki](https://github.com/robbiehanson/KissXML/wiki) articles? Try the **[mailing list](http://groups.google.com/group/kissxml)**.
|
||||
<br/>
|
||||
<br/>
|
||||
Love the project? Wanna buy me a coffee? (or a beer :D) [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=69SPF7R4ZF69J)
|
||||
|
||||
## Changelog
|
||||
|
||||
* 5.0.2 - Jan 26 2016 - Enable Swift support via `libxml/module.modulemap` and `DDXML_LIBXML_MODULE_ENABLED` macro. You can use the `KissXML/libxml_module` CocoaPods subspec to enable this feature.
|
||||
* 5.0.1 - Jan 21 2016 - Run tests on iOS and Mac targets.
|
||||
Reference in new issue
Block a user