Index: src/OFXMLElement.h
==================================================================
--- src/OFXMLElement.h
+++ src/OFXMLElement.h
@@ -207,35 +207,74 @@
*/
- (OFString*)stringValue;
/**
* Adds the specified attribute.
+ *
+ * If an attribute with the same name and namespace already exists, it is not
+ * added.
*
* \param attr The attribute to add
*/
- (void)addAttribute: (OFXMLAttribute*)attr;
/**
* Adds the specified attribute with the specified value.
+ *
+ * If an attribute with the same name and namespace already exists, it is not
+ * added.
*
* \param name The name of the attribute
* \param value The value of the attribute
*/
- (void)addAttributeWithName: (OFString*)name
stringValue: (OFString*)value;
/**
* Adds the specified attribute with the specified namespace and value.
+ *
+ * If an attribute with the same name and namespace already exists, it is not
+ * added.
*
* \param name The name of the attribute
* \param ns The namespace of the attribute
* \param value The value of the attribute
*/
- (void)addAttributeWithName: (OFString*)name
namespace: (OFString*)ns
stringValue: (OFString*)value;
+/**
+ * \param attrname The name of the attribute
+ * \return The attribute with the specified name
+ */
+- (OFXMLAttribute*)attributeForName: (OFString*)attrname;
+
+/**
+ * \param attrname The name of the attribute
+ * \param attrns The namespace of the attribute
+ * \return The attribute with the specified name and namespace
+ */
+- (OFXMLAttribute*)attributeForName: (OFString*)attrname
+ namespace: (OFString*)attrns;
+
+/**
+ * Removes the attribute with the specified name.
+ *
+ * \param attrname The name of the attribute
+ */
+- (void)removeAttributeForName: (OFString*)attrname;
+
+/**
+ * Removes the attribute with the specified name and namespace.
+ *
+ * \param attrname The name of the attribute
+ * \param attrns The namespace of the attribute
+ */
+- (void)removeAttributeForName: (OFString*)attrname
+ namespace: (OFString*)attrns;
+
/**
* Sets a prefix for a namespace.
*
* \param prefix The prefix for the namespace
* \param ns The namespace for which the prefix is set
Index: src/OFXMLElement.m
==================================================================
--- src/OFXMLElement.m
+++ src/OFXMLElement.m
@@ -422,29 +422,21 @@
selector: _cmd];
if (attributes == nil)
attributes = [[OFMutableArray alloc] init];
- /* FIXME: Prevent having it twice! */
-
- [attributes addObject: attr];
+ if ([self attributeForName: attr->name
+ namespace: attr->ns] == nil)
+ [attributes addObject: attr];
}
- (void)addAttributeWithName: (OFString*)name_
stringValue: (OFString*)value
{
- OFAutoreleasePool *pool;
-
- if (name == nil)
- @throw [OFInvalidArgumentException newWithClass: isa
- selector: _cmd];
-
- pool = [[OFAutoreleasePool alloc] init];
- [self addAttribute: [OFXMLAttribute attributeWithName: name_
- namespace: nil
- stringValue: value]];
- [pool release];
+ [self addAttributeWithName: name_
+ namespace: nil
+ stringValue: value];
}
- (void)addAttributeWithName: (OFString*)name_
namespace: (OFString*)ns_
stringValue: (OFString*)value
@@ -460,12 +452,69 @@
namespace: ns_
stringValue: value]];
[pool release];
}
-/* TODO: Replace attribute */
-/* TODO: Remove attribute */
+- (OFXMLAttribute*)attributeForName: (OFString*)attrname
+{
+ return [self attributeForName: attrname
+ namespace: nil];
+}
+
+- (OFXMLAttribute*)attributeForName: (OFString*)attrname
+ namespace: (OFString*)attrns
+{
+ OFXMLAttribute **attrs_c = [attributes cArray];
+ size_t i, attrs_count = [attributes count];
+
+ if (attrns != nil) {
+ for (i = 0; i < attrs_count; i++)
+ if ([attrs_c[i]->ns isEqual: attrns] &&
+ [attrs_c[i]->name isEqual: attrname])
+ return attrs_c[i];
+ } else {
+ for (i = 0; i < attrs_count; i++)
+ if (attrs_c[i]->ns == nil &&
+ [attrs_c[i]->name isEqual: attrname])
+ return attrs_c[i];
+ }
+
+ return nil;
+}
+
+- (void)removeAttributeForName: (OFString*)attrname
+{
+ [self removeAttributeForName: attrname
+ namespace: nil];
+}
+
+- (void)removeAttributeForName: (OFString*)attrname
+ namespace: (OFString*)attrns
+{
+ OFXMLAttribute **attrs_c = [attributes cArray];
+ size_t i, attrs_count = [attributes count];
+
+ if (attrns != nil) {
+ for (i = 0; i < attrs_count; i++) {
+ if ([attrs_c[i]->ns isEqual: attrns] &&
+ [attrs_c[i]->name isEqual: attrname]) {
+ [attributes removeObjectAtIndex: i];
+
+ return;
+ }
+ }
+ } else {
+ for (i = 0; i < attrs_count; i++) {
+ if (attrs_c[i]->ns == nil &&
+ [attrs_c[i]->name isEqual: attrname]) {
+ [attributes removeObjectAtIndex: i];
+
+ return;
+ }
+ }
+ }
+}
- (void)setPrefix: (OFString*)prefix
forNamespace: (OFString*)ns_
{
if (name == nil || prefix == nil || [prefix isEqual: @""])
Index: tests/OFXMLElementTests.m
==================================================================
--- tests/OFXMLElementTests.m
+++ tests/OFXMLElementTests.m
@@ -92,13 +92,24 @@
TEST(@"-[addAttributeWithName:namespace:stringValue:]",
R([elem[1] addAttributeWithName: @"foo"
namespace: @"urn:objfw:test"
stringValue: @"bar"]) &&
+ R([elem[1] addAttributeWithName: @"foo"
+ namespace: @"urn:objfw:test"
+ stringValue: @"ignored"]) &&
[[elem[1] stringValue] isEqual:
@"b&ar"])
+ TEST(@"-[removeAttributeForName:namespace:]",
+ R([elem[1] removeAttributeForName: @"foo"]) &&
+ [[elem[1] stringValue] isEqual:
+ @"b&ar"] &&
+ R([elem[1] removeAttributeForName: @"foo"
+ namespace: @"urn:objfw:test"]) &&
+ [[elem[1] stringValue] isEqual: @"b&ar"])
+
TEST(@"-[addChild:]",
R([elem[0] addChild: [OFXMLElement elementWithName: @"bar"]]) &&
[[elem[0] stringValue] isEqual:
@""] &&
R([elem[2] addChild: [OFXMLElement elementWithName: @"bar"