mirror of
https://bitbucket.org/vendoo/vendoo_v1.0.git
synced 2025-12-25 11:47:40 +00:00
257 lines
9.2 KiB
Objective-C
257 lines
9.2 KiB
Objective-C
//
|
|
// PicoXMLWriter.m
|
|
// pico
|
|
//
|
|
// Created by bulldog on 13-2-26.
|
|
// Copyright (c) 2013 LeanSoft Technology. All rights reserved.
|
|
//
|
|
|
|
#import "PicoXMLWriter.h"
|
|
#import "PicoConverter.h"
|
|
#import "XMLWriter.h"
|
|
#import "PicoConfig.h"
|
|
#import "PicoBindingSchema.h"
|
|
#import "PicoClassSchema.h"
|
|
#import "PicoPropertySchema.h"
|
|
#import "PicoConstants.h"
|
|
#import "PicoXMLElement.h"
|
|
#import "PicoBindable.h"
|
|
|
|
@implementation PicoXMLWriter
|
|
|
|
@synthesize config = _config;
|
|
|
|
- (instancetype)init {
|
|
return [self initWithConfig:[[PicoConfig alloc] init]];
|
|
}
|
|
|
|
- (instancetype)initWithConfig:(PicoConfig *)config {
|
|
self = [super init];
|
|
if (self) {
|
|
self.config = config;
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
-(NSData *)toData:(id)obj {
|
|
|
|
NSString *xmlString = [self toString:obj] ;
|
|
|
|
NSData *data = [xmlString dataUsingEncoding: CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef)self.config.encoding)) allowLossyConversion:NO];
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
-(NSString *)toString:(id)obj {
|
|
|
|
|
|
if (obj == nil) {
|
|
@throw [NSException exceptionWithName:@"WriterException" reason:@"Can't write nil object." userInfo:nil];
|
|
}
|
|
|
|
XMLWriter *xmlWriter = [[XMLWriter alloc] init];
|
|
_autoPrefixCount = 0;
|
|
|
|
[xmlWriter writeStartDocumentWithEncodingAndVersion:self.config.encoding version:@"1.0"];
|
|
|
|
|
|
PicoBindingSchema *bindingSchema = [PicoBindingSchema fromObject:obj];
|
|
PicoClassSchema *classSchema = [bindingSchema classSchema];
|
|
NSString *xmlName = classSchema.xmlName;
|
|
NSString *namespace = classSchema.nsURI;
|
|
if (!xmlName) { // workaround, in case xml name is not provided in class schema, use class name instead
|
|
xmlName = bindingSchema.className;
|
|
}
|
|
|
|
if ([namespace length] != 0) {
|
|
[xmlWriter setDefaultNamespace:namespace]; // bind to default namespace
|
|
}
|
|
|
|
[xmlWriter writeStartElementWithNamespace:namespace localName:xmlName];
|
|
|
|
[self writeObject:xmlWriter source:obj];
|
|
|
|
[xmlWriter writeEndElementWithNamespace:namespace localName:xmlName];
|
|
|
|
[xmlWriter writeEndDocument];
|
|
|
|
NSString *xmlString = [xmlWriter toString];
|
|
xmlString = [NSMutableString stringWithString:xmlString];
|
|
|
|
|
|
return xmlString;
|
|
|
|
}
|
|
|
|
-(void)writeObject:(XMLWriter *)xmlWriter source:(id)source {
|
|
PicoBindingSchema *bindingSchema = [PicoBindingSchema fromObject:source];
|
|
NSString *namespace = nil;
|
|
PicoClassSchema *classSchema = [bindingSchema classSchema];
|
|
if (classSchema) {
|
|
namespace = classSchema.nsURI;
|
|
}
|
|
|
|
[self writeAttributes:xmlWriter source:source schema:bindingSchema];
|
|
|
|
[self writeValue:xmlWriter source:source schema:bindingSchema];
|
|
|
|
// automatic prefixing
|
|
if (namespace && ![xmlWriter getPrefix:namespace]) {
|
|
NSString *prefix = [NSString stringWithFormat:@"ns%d", _autoPrefixCount++];
|
|
[xmlWriter setPrefix:prefix namespaceURI:namespace];
|
|
}
|
|
[self writeElements:xmlWriter source:source schema:bindingSchema namespace:namespace];
|
|
|
|
[self writeAnyElements:xmlWriter source:source schema:bindingSchema];
|
|
}
|
|
|
|
-(void)writeAttributes:(XMLWriter *)xmlWriter source:(id)source schema:(PicoBindingSchema *)bindingSchema {
|
|
NSDictionary *map = bindingSchema.property2AttributeSchemaMapping;
|
|
if (map.count > 0) {
|
|
for(NSString *propertyName in map) {
|
|
PicoPropertySchema *ps = map[propertyName];
|
|
id propertyValue = [source valueForKey:propertyName];
|
|
if (propertyValue) {
|
|
NSString *xmlString = [PicoConverter write:propertyValue withType:ps.propertyType config:self.config];
|
|
if (xmlString.length > 0) {
|
|
[xmlWriter writeAttribute:ps.xmlName value:xmlString];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-(void)writeValue:(XMLWriter *)xmlWriter source:(id)source schema:(PicoBindingSchema *)bindingSchema {
|
|
PicoPropertySchema *valuePs = bindingSchema.valueSchema;
|
|
if (valuePs) {
|
|
id propertyValue = [source valueForKey:valuePs.propertyName];
|
|
NSString *xmlString = [PicoConverter write:propertyValue withType:valuePs.propertyType config:self.config];
|
|
if (xmlString.length > 0) {
|
|
[xmlWriter writeCharacters:xmlString];
|
|
}
|
|
}
|
|
}
|
|
|
|
-(void)writeAnyElements:(XMLWriter *)xmlWriter source:(id)source schema:(PicoBindingSchema *)bindingSchema {
|
|
PicoPropertySchema *anyPs = bindingSchema.anyElementSchema;
|
|
if(anyPs) {
|
|
NSArray *anyArray = [source valueForKey: anyPs.propertyName];
|
|
if (anyArray) {
|
|
for(id entry in anyArray) {
|
|
if (entry) {
|
|
if ([entry isMemberOfClass:[PicoXMLElement class]]) {
|
|
[self writePicoXMLElement:xmlWriter xmlElement:entry];
|
|
} else if ([entry conformsToProtocol:@protocol(PicoBindable)]) {
|
|
[self writePicoObject:xmlWriter source:entry];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
-(void)writePicoXMLElement:(XMLWriter *)xmlWriter xmlElement:(PicoXMLElement *)element {
|
|
if (!element) return; // to be cautious
|
|
if (element.name) {
|
|
NSString *namespace = element.nsUri;
|
|
if (namespace.length == 0) {
|
|
namespace = nil;
|
|
}
|
|
// automatic prefixing
|
|
if (namespace && ![xmlWriter getPrefix:namespace]) {
|
|
NSString *prefix = [NSString stringWithFormat:@"ns%d", _autoPrefixCount++];
|
|
[xmlWriter setPrefix:prefix namespaceURI:namespace];
|
|
}
|
|
[xmlWriter writeStartElementWithNamespace:namespace localName:element.name];
|
|
if (element.attributes) { // write attributes
|
|
for(NSString *key in element.attributes) {
|
|
NSString *value = [element.attributes valueForKey:key];
|
|
[xmlWriter writeAttribute:key value:value];
|
|
}
|
|
}
|
|
if (element.value) { // write element text
|
|
[xmlWriter writeCharacters:element.value];
|
|
}
|
|
if (element.children) { // write element children
|
|
for(PicoXMLElement *child in element.children) {
|
|
[self writePicoXMLElement:xmlWriter xmlElement:child];
|
|
}
|
|
}
|
|
[xmlWriter writeEndElementWithNamespace:namespace localName:element.name];
|
|
}
|
|
}
|
|
|
|
-(void)writePicoObject:(XMLWriter *)xmlWriter source:(id)source {
|
|
if (!source) return; // to be cautious
|
|
PicoBindingSchema *bindingSchema = [PicoBindingSchema fromObject:source];
|
|
PicoClassSchema *classSchema = [bindingSchema classSchema];
|
|
NSString *xmlName = classSchema.xmlName;
|
|
NSString *namespace = classSchema.nsURI;
|
|
if (!xmlName) { // workaround, in case xml name is not provided in class schema, use class name instead
|
|
xmlName = bindingSchema.className;
|
|
}
|
|
|
|
// automatic prefixing
|
|
if (namespace && ![xmlWriter getPrefix:namespace]) {
|
|
NSString *prefix = [NSString stringWithFormat:@"ns%d", _autoPrefixCount++];
|
|
[xmlWriter setPrefix:prefix namespaceURI:namespace];
|
|
}
|
|
[xmlWriter writeStartElementWithNamespace:namespace localName:xmlName];
|
|
[self writeObject:xmlWriter source:source];
|
|
[xmlWriter writeEndElementWithNamespace:namespace localName:xmlName];
|
|
}
|
|
|
|
|
|
-(void)writeElements:(XMLWriter *)xmlWriter source:(id)source schema:(PicoBindingSchema *)bindingSchema namespace:(NSString *)nsURI {
|
|
NSDictionary *map = bindingSchema.property2ElementSchemaMapping;
|
|
if (map.count > 0) {
|
|
for(NSString *propertyName in map) {
|
|
PicoPropertySchema *ps = map[propertyName];
|
|
id propertyValue = [source valueForKey:propertyName];
|
|
if (propertyValue) {
|
|
if ([ps.propertyKind isEqualToString:PICO_KIND_ELEMENT]) {
|
|
[self writeElement:xmlWriter source:propertyValue schema:ps namespace:nsURI];
|
|
}
|
|
// array elements
|
|
else if ([ps.propertyKind isEqualToString:PICO_KIND_ELEMENT_ARRAY]) {
|
|
NSArray *array = propertyValue;
|
|
for(id entry in array) {
|
|
if (entry) {
|
|
[self writeElement:xmlWriter source:entry schema:ps namespace:nsURI];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
-(void)writeElement:(XMLWriter *)xmlWriter source:(id)source schema:(PicoPropertySchema *)propertySchema namespace:(NSString *)nsURI {
|
|
if (!source) return;
|
|
|
|
if ([PicoConverter isPrimitive:propertySchema.propertyType]) {
|
|
NSString *xmlString = [PicoConverter write:source withType:propertySchema.propertyType config:self.config];
|
|
if (xmlString.length > 0) {
|
|
[xmlWriter writeStartElementWithNamespace:nsURI localName:propertySchema.xmlName];
|
|
[xmlWriter writeCharacters:xmlString];
|
|
[xmlWriter writeEndElementWithNamespace:nsURI localName:propertySchema.xmlName];
|
|
}
|
|
return;
|
|
}
|
|
|
|
if ([propertySchema.propertyType isEqualToString:PICO_TYPE_OBJECT]) {
|
|
[xmlWriter writeStartElementWithNamespace:nsURI localName:propertySchema.xmlName];
|
|
[self writeObject:xmlWriter source:source];
|
|
[xmlWriter writeEndElementWithNamespace:nsURI localName:propertySchema.xmlName];
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|