Estoy tratando de analizar un XML que estoy obteniendo de un servicio web con un NSXMLParserDelegate
. los NSObject
Quiero poner los datos (solo lo llamaré MyObject
) posee @property
S que no es NSString
S (hay algunos NSDate
S, algunos NSNumber
S, y tal vez en algún momento en el futuro algunas primitivas).
Dado que el XML es todo una gran cadena, estoy recibiendo errores y bloqueos cuando intento poner directamente los valores de la XML en mis propiedades (estoy usando [myObject setValue:currentElementValue forKey:elementName];
en mi parser:didEndElement:...
, que normalmente funciona bien, cuando key
es un NSString
). Realmente no esperaba que esto funcionara, pero pensé que valía la pena.
Lo más fácil de hacer es tenerlo todo, así que si tengo un '@property (no atómico, fuerte) nsnumber *edad;' en mi objeto, cuando encuentro el <age>25</age>
parte de mi XML, lo hago MyObject.age = [NSNumber numberWithInt:[currentElementValue intValue]];
. El problema con esto es que es muy rígido: me gustaría que este código sea más dinámico que eso. No quiero tener que saber cuáles son todas las propiedades de mi objeto con anticipación.
También he intentado comprobar lo que el class
de la propiedad es, luego hacer alguna conversión antes de ingresar un valor (por lo que algo como [myObject setValue:[NSNumber numberWithInt:[currentElementValue intValue] forKey:elementName];
Si la propiedad isKindOfClass:[NSNumber class]]
. El problema con esto es que esta es la primera vez que se usa la propiedad, por lo que es nil
, y por lo tanto no tiene clase. Así que este enfoque tampoco funciona realmente.
¿Estoy haciendo esto completamente mal? Parece que debería ser bastante típico obtener datos de un XML y ponerlos en noNSString
Variables, pero parece que no puedo hacer que funcione.
Si alguien necesita ver más código para comprender mejor cómo estoy configurado o qué he probado, avíseme.
Editar: se me ocurrió un ejemplo rápido de lo que estoy tratando de hacer. Supongamos que tengo el siguiente XML:
<Object>
<ITEM_NUMBER>4</ITEM_NUMBER>
<IS_AWESOME>YES</IS_AWESOME>
<AWESOMENESS>9000.1</AWESOMENESS>
</Object>
que quiero analizar en una instancia de MyObject
(un NSObject
subclase)
@interface MyObject: NSObject
@property (nonatomic, assign) int ITEM_NUMBER;
@property (nonatomic, assign) BOOL IS_AWESOME;
@property (nonatomic, assign) float AWESOMENESS;
@end
Y un segundo XML
<OtherObject>
<PRICE>4.99</PRICE>
<QUANTITY>5</QUANTITY>
<FOR_RESALE>NO</FOR_RESALE>
</OtherObject>
que entrará en una instancia de OtherObject
(además NSObject
subclase)
@interface OtherObject: NSObject
@property (nonatomic, assign) int QUANTITY;
@property (nonatomic, assign) BOOL FOR_RESALE;
@property (nonatomic, assign) float PRICE;
@end
Quiero crear un analizador de "plantilla" (que tiene @property (nonatomic, strong) NSObject *instance;
y entonces NSMutableString *currentElementValue
como un ivar)
...
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
[currentElementValue setString:string];
}
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([[self.instance valueForKey:elementName] isKindOfClass:int])
{
[self.instance setValue:[currentElementValue intValue] forKey:elementName];
}
else if ([[self.instance valueForKey:elementName] isKindOfClass:float])
{
[self.instance setValue:[currentElementValue floatValue] forKey:elementName];
}
else if ([[self.instance valueForKey:elementName] isKindOfClass:BOOL])
{
[self.instance setValue:[currentElementValue boolValue] forKey:elementName];
}
else if ...
}
...
Entonces, solo subclase ese analizador de "plantilla" para cada uno de mis diferentes XML y sobrescribir el init
método para que
self.instance = [[MyObject alloc] init];
o
self.instance = [[OtherObject alloc] init];
según sea apropiado. Tengo muchos servicios web que estoy llamando que obtendré XML estructurado de manera similar, por lo que solo tener que cambiar 1 línea en los analizadores para cada uno es algo que es muy deseable. Tener todo el resto del código analizador en una sola clase de "plantilla" facilitará el mantenimiento, la lectura y la depuración del código.
Obviamente, el problema que tengo es isKindOfClass
no acepta int
, float
, o BOOL
como entradas. ¿Hay algo similar que pueda usar en su lugar?