Index: src/OFXMLElement.h
==================================================================
--- src/OFXMLElement.h
+++ src/OFXMLElement.h
@@ -14,18 +14,76 @@
#import "OFDictionary.h"
#import "OFArray.h"
extern int _OFXMLElement_reference;
+/**
+ * The OFXMLAttribute represents an attribute of an XML element as an object.
+ */
+@interface OFXMLAttribute: OFObject
+{
+ OFString *prefix;
+ OFString *name;
+ OFString *ns;
+ OFString *value;
+}
+
+/**
+ * \param name The name of the attribute
+ * \param prefix The prefix of the attribute
+ * \param ns The namespace of the attribute
+ * \param value The string value of the attribute
+ * \return A new autoreleased OFXMLAttribute with the specified parameters
+ */
++ attributeWithName: (OFString*)name
+ prefix: (OFString*)prefix
+ namespace: (OFString*)ns
+ stringValue: (OFString*)value;
+
+/**
+ * Initializes an already allocated OFXMLAttribute.
+ *
+ * \param name The name of the attribute
+ * \param prefix The prefix of the attribute
+ * \param ns The namespace of the attribute
+ * \param value The string value of the attribute
+ * \return An initialized OFXMLAttribute with the specified parameters
+ */
+- initWithName: (OFString*)name
+ prefix: (OFString*)prefix
+ namespace: (OFString*)ns
+ stringValue: (OFString*)value;
+
+/**
+ * \return The name of the attribute as an autoreleased OFString
+ */
+- (OFString*)name;
+
+/**
+ * \return The prefix of the attribute as an autoreleased OFString
+ */
+- (OFString*)prefix;
+
+/**
+ * \return The namespace of the attribute as an autoreleased OFString
+ */
+- (OFString*)namespace;
+
+/**
+ * \return The string value of the attribute as an autoreleased OFString
+ */
+- (OFString*)stringValue;
+@end
+
/**
* The OFXMLElement represents an XML element as an object which can be
* modified and converted back to XML again.
*/
@interface OFXMLElement: OFObject
{
OFString *name;
- OFDictionary *attrs;
+ OFArray *attrs;
OFString *stringval;
OFArray *children;
}
/**
@@ -67,10 +125,17 @@
* \return A new autoreleased OFString representing the OFXMLElement as an
* XML string
*/
- (OFString*)string;
+/**
+ * Adds the specified attribute.
+ *
+ * \param attr The attribute to add
+ */
+- addAttribute: (OFXMLAttribute*)attr;
+
/**
* Adds the specified attribute with the specified value.
*
* \param name The name of the attribute
* \param value The value of the attribute
Index: src/OFXMLElement.m
==================================================================
--- src/OFXMLElement.m
+++ src/OFXMLElement.m
@@ -18,10 +18,68 @@
#import "OFXMLElement.h"
#import "OFAutoreleasePool.h"
#import "OFExceptions.h"
int _OFXMLElement_reference;
+
+@implementation OFXMLAttribute
++ attributeWithName: (OFString*)name_
+ prefix: (OFString*)prefix_
+ namespace: (OFString*)ns_
+ stringValue: (OFString*)value_
+{
+ return [[[self alloc] initWithName: name_
+ prefix: prefix_
+ namespace: ns_
+ stringValue: value_] autorelease];
+}
+
+- initWithName: (OFString*)name_
+ prefix: (OFString*)prefix_
+ namespace: (OFString*)ns_
+ stringValue: (OFString*)value_
+{
+ self = [super init];
+
+ name = [name_ copy];
+ prefix = [prefix_ copy];
+ ns = [ns_ copy];
+ value = [value_ copy];
+
+ return self;
+}
+
+- (void)dealloc
+{
+ [name release];
+ [prefix release];
+ [ns release];
+ [value release];
+
+ [super dealloc];
+}
+
+- (OFString*)name
+{
+ return [[name copy] autorelease];
+}
+
+- (OFString*)prefix
+{
+ return [[prefix copy] autorelease];
+}
+
+- (OFString*)namespace
+{
+ return [[ns copy] autorelease];
+}
+
+- (OFString*)stringValue
+{
+ return [[value copy] autorelease];
+}
+@end
@implementation OFXMLElement
+ elementWithName: (OFString*)name_
{
return [[[self alloc] initWithName: name_] autorelease];
@@ -62,11 +120,12 @@
- (OFString*)string
{
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
char *str_c;
- size_t len, i, j;
+ size_t len, i, j, attrs_count;
+ OFXMLAttribute **attrs_data;
OFString *ret, *tmp;
len = [name length] + 4;
str_c = [self allocMemoryWithSize: len];
@@ -74,44 +133,38 @@
*str_c = '<';
memcpy(str_c + 1, [name cString], [name length]);
i = [name length] + 1;
/* Attributes */
- if (attrs != nil) {
- OFIterator *iter = [attrs iterator];
-
- for (;;) {
- of_iterator_pair_t pair;
-
- pair = [iter nextKeyObjectPair];
-
- if (pair.key == nil || pair.object == nil)
- break;
-
- tmp = [pair.object stringByXMLEscaping];
-
- len += [pair.key length] + [tmp length] + 4;
- @try {
- str_c = [self resizeMemory: str_c
- toSize: len];
- } @catch (OFException *e) {
- [self freeMemory: str_c];
- @throw e;
- }
-
- str_c[i++] = ' ';
- memcpy(str_c + i, [pair.key cString],
- [pair.key length]);
- i += [pair.key length];
- str_c[i++] = '=';
- str_c[i++] = '\'';
- memcpy(str_c + i, [tmp cString], [tmp length]);
- i += [tmp length];
- str_c[i++] = '\'';
-
- [pool releaseObjects];
- }
+ attrs_data = [attrs data];
+ attrs_count = [attrs count];
+
+ for (j = 0; j < attrs_count; j++) {
+ /* FIXME: Add namespace support */
+ OFString *attr_name = [attrs_data[j] name];
+ tmp = [[attrs_data[j] stringValue] stringByXMLEscaping];
+
+ len += [attr_name length] + [tmp length] + 4;
+ @try {
+ str_c = [self resizeMemory: str_c
+ toSize: len];
+ } @catch (OFException *e) {
+ [self freeMemory: str_c];
+ @throw e;
+ }
+
+ str_c[i++] = ' ';
+ memcpy(str_c + i, [attr_name cString],
+ [attr_name length]);
+ i += [attr_name length];
+ str_c[i++] = '=';
+ str_c[i++] = '\'';
+ memcpy(str_c + i, [tmp cString], [tmp length]);
+ i += [tmp length];
+ str_c[i++] = '\'';
+
+ [pool releaseObjects];
}
/* Childen */
if (stringval != nil || children != nil) {
if (stringval != nil)
@@ -163,21 +216,37 @@
}
return ret;
}
-- addAttributeWithName: (OFString*)name_
- stringValue: (OFString*)value_
+- addAttribute: (OFXMLAttribute*)attr
{
if (attrs == nil)
- attrs = [[OFMutableDictionary alloc] init];
+ attrs = [[OFMutableArray alloc] init];
+
+ /* FIXME: Prevent having it twice! */
+
+ [attrs addObject: attr];
+
+ return self;
+}
- [attrs setObject: value_
- forKey: name_];
+- addAttributeWithName: (OFString*)name_
+ stringValue: (OFString*)value
+{
+ OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
+ [self addAttribute: [OFXMLAttribute attributeWithName: name_
+ prefix: nil
+ namespace: nil
+ stringValue: value]];
+ [pool release];
return self;
}
+
+/* TODO: Replace attribute */
+/* TODO: Remove attribute */
- addChild: (OFXMLElement*)child
{
if (stringval != nil)
@throw [OFInvalidArgumentException newWithClass: isa
Index: src/OFXMLParser.h
==================================================================
--- src/OFXMLParser.h
+++ src/OFXMLParser.h
@@ -9,11 +9,10 @@
* the packaging of this file.
*/
#import "OFObject.h"
#import "OFString.h"
-#import "OFDictionary.h"
extern int _OFXMLParser_reference;
@class OFXMLParser;
@@ -20,11 +19,11 @@
@protocol OFXMLParserDelegate
- (BOOL)xmlParser: (OFXMLParser*)parser
didStartTagWithName: (OFString*)name
prefix: (OFString*)prefix
namespace: (OFString*)ns
- attributes: (OFDictionary*)attrs;
+ attributes: (OFArray*)attrs;
- (BOOL)xmlParser: (OFXMLParser*)parser
didEndTagWithName: (OFString*)name
prefix: (OFString*)prefix
namespace: (OFString*)ns;
- (BOOL)xmlParser: (OFXMLParser*)parser
@@ -54,12 +53,13 @@
} state;
OFString *cache;
OFString *name;
OFString *prefix;
OFString *ns;
- OFDictionary *attrs;
+ OFArray *attrs;
OFString *attr_name;
+ OFString *attr_prefix;
char delim;
OFArray *previous;
}
+ xmlParser;
Index: src/OFXMLParser.m
==================================================================
--- src/OFXMLParser.m
+++ src/OFXMLParser.m
@@ -97,10 +97,11 @@
[name release];
[prefix release];
[ns release];
[attrs release];
[attr_name release];
+ [attr_prefix release];
[previous release];
[super dealloc];
}
@@ -182,22 +183,20 @@
cache_c = [cache cString];
cache_len = [cache length];
if ((tmp = memchr(cache_c, ':',
cache_len)) != NULL) {
- prefix = [[OFString alloc]
- initWithCString: cache_c
- length: tmp - cache_c];
name = [[OFString alloc]
initWithCString: tmp + 1
length: cache_len - (tmp -
cache_c) - 1];
- } else {
- prefix = nil;
- name = [[OFString alloc]
+ prefix = [[OFString alloc]
initWithCString: cache_c
- length: cache_len];
+ length: tmp - cache_c];
+ } else {
+ name = [cache copy];
+ prefix = nil;
}
if (buf[i] == '>' || buf[i] == '/') {
pool = [[OFAutoreleasePool alloc] init];
@@ -246,22 +245,20 @@
cache_c = [cache cString];
cache_len = [cache length];
if ((tmp = memchr(cache_c, ':',
cache_len)) != NULL) {
- prefix = [[OFString alloc]
- initWithCString: cache_c
- length: tmp - cache_c];
name = [[OFString alloc]
initWithCString: tmp + 1
length: cache_len - (tmp -
cache_c) - 1];
- } else {
- prefix = nil;
- name = [[OFString alloc]
+ prefix = [[OFString alloc]
initWithCString: cache_c
- length: cache_len];
+ length: tmp - cache_c];
+ } else {
+ name = [cache copy];
+ prefix = nil;
}
if (![[previous lastObject] isEqual: cache])
@throw [OFMalformedXMLException
newWithClass: isa];
@@ -335,16 +332,35 @@
break;
/* Looking for attribute name */
case OF_XMLPARSER_IN_ATTR_NAME:
if (buf[i] == '=') {
+ const char *cache_c, *tmp;
+ size_t cache_len;
+
len = i - last;
if (len > 0)
[cache appendCString: buf + last
withLength: len];
- attr_name = [cache copy];
+ cache_c = [cache cString];
+ cache_len = [cache length];
+
+ if ((tmp = memchr(cache_c, ':',
+ cache_len)) != NULL ) {
+ attr_name = [[OFString alloc]
+ initWithCString: tmp + 1
+ length: cache_len - (tmp -
+ cache_c) - 1];
+ attr_prefix = [[OFString alloc]
+ initWithCString: cache_c
+ length: tmp - cache_c];
+ } else {
+ attr_name = [cache copy];
+ attr_prefix = nil;
+ }
+
[cache setToCString: ""];
last = i + 1;
state = OF_XMLPARSER_EXPECT_DELIM;
}
@@ -370,22 +386,27 @@
if (len > 0)
[cache appendCString: buf + last
withLength: len];
if (attrs == nil)
- attrs =
- [[OFMutableDictionary alloc] init];
+ attrs = [[OFMutableArray alloc] init];
pool = [[OFAutoreleasePool alloc] init];
attr_val = [cache
stringByXMLUnescapingWithHandler: self];
- [attrs setObject: attr_val
- forKey: attr_name];
+ [attrs addObject: [OFXMLAttribute
+ attributeWithName: attr_name
+ prefix: attr_prefix
+ namespace: nil
+ stringValue: attr_val]];
[pool release];
[cache setToCString: ""];
[attr_name release];
+ [attr_prefix release];
+ attr_name = nil;
+ attr_prefix = nil;
last = i + 1;
state = OF_XMLPARSER_IN_TAG;
}
break;
Index: tests/OFXMLParser/OFXMLParser.m
==================================================================
--- tests/OFXMLParser/OFXMLParser.m
+++ tests/OFXMLParser/OFXMLParser.m
@@ -22,29 +22,33 @@
@implementation ParserDelegate
- (BOOL)xmlParser: (OFXMLParser*)parser
didStartTagWithName: (OFString*)name
prefix: (OFString*)prefix
namespace: (OFString*)ns
- attributes: (OFDictionary*)attrs
+ attributes: (OFArray*)attrs
{
+ OFXMLAttribute **attrs_data;
+ size_t i, attrs_count;
+
printf("START\nname=\"%s\"\nprefix=\"%s\"\nns=\"%s\"\n",
[name cString], [prefix cString], [ns cString]);
- if (attrs) {
- OFIterator *iter = [attrs iterator];
-
- for (;;) {
- of_iterator_pair_t pair;
-
- pair = [iter nextKeyObjectPair];
-
- if (pair.key == nil || pair.object == nil)
- break;
-
- printf("ATTR: \"%s\"=\"%s\"\n",
- [pair.key cString], [pair.object cString]);
- }
+ attrs_data = [attrs data];
+ attrs_count = [attrs count];
+
+ for (i = 0; i < attrs_count; i++) {
+ OFString *attr_name = [attrs_data[i] name];
+ OFString *attr_prefix = [attrs_data[i] prefix];
+ OFString *attr_ns = [attrs_data[i] namespace];
+ OFString *attr_value = [attrs_data[i] stringValue];
+
+ printf("ATTR:\n name=\"%s\"\n", [attr_name cString]);
+ if (attr_prefix != nil)
+ printf(" prefix=\"%s\"\n", [attr_prefix cString]);
+ if (attr_ns != nil)
+ printf(" ns=\"%s\"\n", [attr_ns cString]);
+ printf(" value=\"%s\"\n", [attr_value cString]);
}
puts("");
return YES;
@@ -80,12 +84,13 @@
@end
int
main()
{
- const char *foo = "barfoo<bar"
- "barquxbar";
+ const char *foo = "bar"
+ "foo<barbarquxbar"
+ "";
size_t len = strlen(foo);
size_t i;
OFXMLParser *parser = [OFXMLParser xmlParser];
[parser setDelegate: [[ParserDelegate alloc] init]];