blob: 7d772be1fd316ff53c450fee0592916cdd3629de [file] [log] [blame]
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#import "CMISAtomEntryParser.h"
#import "CMISAtomLink.h"
#import "CMISRenditionData.h"
#import "CMISAtomParserUtil.h"
@interface CMISAtomEntryParser ()
@property (nonatomic, strong, readwrite) CMISObjectData *objectData;
@property (nonatomic, strong) NSData *atomData;
@property (nonatomic, strong) NSString *currentPropertyType;
@property (nonatomic, strong) CMISPropertyData *currentPropertyData;
@property (nonatomic, strong) NSMutableArray *propertyValues;
@property (nonatomic, strong) CMISProperties *currentObjectProperties;
@property (nonatomic, strong) NSMutableSet *currentLinkRelations;
@property (nonatomic, strong) CMISRenditionData *currentRendition;
@property (nonatomic, strong) NSMutableArray *currentRenditions;
@property (nonatomic, strong) NSMutableString *string;
@property (nonatomic, assign) BOOL parsingRelationship;
@property (nonatomic, weak) id<NSXMLParserDelegate, CMISAtomEntryParserDelegate> parentDelegate;
@property (nonatomic, strong) NSDictionary *entryAttributesDict;
// Designated initializer
- (id)init;
// Initializer used if this parser is a delegated child parser
- (id)initWithAtomEntryAttributes:(NSDictionary *)attributes parentDelegate:(id<NSXMLParserDelegate, CMISAtomEntryParserDelegate>)parentDelegate parser:(NSXMLParser *)parser;
@end
@implementation CMISAtomEntryParser
// Designated Initializer
- (id)init
{
self = [super init];
if (self) {
self.currentLinkRelations = [NSMutableSet set];
self.parsingRelationship = NO;
}
return self;
}
- (id)initWithData:(NSData *)atomData
{
self = [self init];
if (self) {
self.atomData = atomData;
}
return self;
}
- (BOOL)parseAndReturnError:(NSError **)error;
{
BOOL parseSuccessful = YES;
// create objects to populate during parse
self.objectData = [[CMISObjectData alloc] init];
// parse the AtomPub data
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:self.atomData];
[parser setShouldProcessNamespaces:YES];
[parser setDelegate:self];
parseSuccessful = [parser parse];
if (!parseSuccessful){
if (error) {
*error = [parser parserError];
}
}
return parseSuccessful;
}
- (id)initWithAtomEntryAttributes:(NSDictionary *)attributes parentDelegate:(id<NSXMLParserDelegate, CMISAtomEntryParserDelegate>)parentDelegate parser:(NSXMLParser *)parser
{
self = [self init];
if (self) {
self.objectData = [[CMISObjectData alloc] init];
self.entryAttributesDict = attributes;
self.parentDelegate = parentDelegate;
self.parsingRelationship = NO;
// Setting ourself, the entry parser, as the delegate, we reset back to our parent when we're done
[parser setDelegate:self];
}
return self;
}
+ (id)atomEntryParserWithAtomEntryAttributes:(NSDictionary *)attributes
parentDelegate:(id<NSXMLParserDelegate,CMISAtomEntryParserDelegate>)parentDelegate
parser:(NSXMLParser *)parser
{
return [[self alloc] initWithAtomEntryAttributes:attributes parentDelegate:parentDelegate parser:parser];
}
#pragma mark -
#pragma mark NSXMLParser delegate methods
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if ([namespaceURI isEqualToString:kCMISNamespaceCmis] && !self.parsingRelationship) {
if ([elementName isEqualToString:kCMISAtomEntryPropertyId] ||
[elementName isEqualToString:kCMISAtomEntryPropertyString] ||
[elementName isEqualToString:kCMISAtomEntryPropertyInteger] ||
[elementName isEqualToString:kCMISAtomEntryPropertyDateTime] ||
[elementName isEqualToString:kCMISAtomEntryPropertyBoolean] ||
[elementName isEqualToString:kCMISAtomEntryPropertyUri] ||
[elementName isEqualToString:kCMISAtomEntryPropertyHtml] ||
[elementName isEqualToString:kCMISAtomEntryPropertyDecimal]) {
self.propertyValues = [NSMutableArray array];
// store attribute values in CMISPropertyData object
self.currentPropertyType = elementName;
self.currentPropertyData = [[CMISPropertyData alloc] init];
self.currentPropertyData.identifier = [attributeDict objectForKey:kCMISAtomEntryPropertyDefId];
self.currentPropertyData.queryName = [attributeDict objectForKey:kCMISAtomEntryQueryName];
self.currentPropertyData.displayName = [attributeDict objectForKey:kCMISAtomEntryDisplayName];
} else if ([elementName isEqualToString:kCMISCoreProperties]) {
// create the CMISProperties object to hold all property data
self.currentObjectProperties = [[CMISProperties alloc] init];
// Set ObjectProperties as the current extensionData object
[self pushNewCurrentExtensionData:self.currentObjectProperties];
} else if ([elementName isEqualToString:kCMISCoreRendition]) {
self.currentRendition = [[CMISRenditionData alloc] init];
} else if ([elementName isEqualToString:kCMISAtomEntryAllowableActions]) {
// Delegate parsing to child parser for allowableActions element
self.childParserDelegate = [CMISAllowableActionsParser allowableActionsParserWithParentDelegate:self parser:parser];
} else if ([elementName isEqualToString:kCMISCoreRelationship]) {
// NOTE: we're currently ignoring the relationship element so set a flag to check
self.parsingRelationship = YES;
}
} else if ([namespaceURI isEqualToString:kCMISNamespaceCmisRestAtom]) {
if ([elementName isEqualToString:kCMISAtomEntryObject]) {
// Set object data as the current extensionData object
[self pushNewCurrentExtensionData:self.objectData];
}
} else if ([namespaceURI isEqualToString:kCMISNamespaceAtom]) {
if ([elementName isEqualToString:kCMISAtomEntryLink]) {
NSString *linkType = [attributeDict objectForKey:kCMISAtomEntryType];
NSString *rel = [attributeDict objectForKey:kCMISAtomEntryRel];
NSString *href = [attributeDict objectForKey:kCMISAtomEntryHref];
CMISAtomLink *link = [[CMISAtomLink alloc] initWithRelation:rel type:linkType href:href];
[self.currentLinkRelations addObject:link];
} else if ([elementName isEqualToString:kCMISAtomEntryContent]) {
self.objectData.contentUrl = [NSURL URLWithString:[attributeDict objectForKey:kCMISAtomEntrySrc]];
}
} else if ([namespaceURI isEqualToString:kCMISNamespaceApp]) {
// Nothing to do in this namespace
} else {
if (self.currentExtensionData != nil) {
self.childParserDelegate = [CMISAtomPubExtensionElementParser extensionElementParserWithElementName:elementName namespaceUri:namespaceURI
attributes:attributeDict parentDelegate:self parser:parser];
}
}
self.string = [NSMutableString string];
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
[self.string appendString:string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:kCMISAtomEntryValue]) {
[CMISAtomParserUtil parsePropertyValue:self.string propertyType:self.currentPropertyType addToArray:self.propertyValues];
} else if (self.currentRendition != nil) {
if ([elementName isEqualToString:kCMISCoreStreamId]) {
self.currentRendition.streamId = self.string;
} else if ([elementName isEqualToString:kCMISCoreMimetype]) {
self.currentRendition.mimeType = self.string;
} else if ([elementName isEqualToString:kCMISCoreLength]) {
self.currentRendition.length = [NSNumber numberWithInteger:[self.string integerValue]];
} else if ([elementName isEqualToString:kCMISCoreTitle]) {
self.currentRendition.title = self.string;
} else if ([elementName isEqualToString:kCMISCoreKind]) {
self.currentRendition.kind = self.string;
} else if ([elementName isEqualToString:kCMISCoreHeight]) {
self.currentRendition.height = [NSNumber numberWithInteger:[self.string integerValue]];
} else if ([elementName isEqualToString:kCMISCoreWidth]) {
self.currentRendition.width = [NSNumber numberWithInteger:[self.string integerValue]];
} else if ([elementName isEqualToString:kCMISCoreRenditionDocumentId]) {
self.currentRendition.renditionDocumentId = self.string;
}
}
if ([namespaceURI isEqualToString:kCMISNamespaceCmis]) {
if (!self.parsingRelationship)
{
// ignore the properties within the relationship element
if ([elementName isEqualToString:kCMISAtomEntryPropertyId] ||
[elementName isEqualToString:kCMISAtomEntryPropertyString] ||
[elementName isEqualToString:kCMISAtomEntryPropertyInteger] ||
[elementName isEqualToString:kCMISAtomEntryPropertyDateTime] ||
[elementName isEqualToString:kCMISAtomEntryPropertyBoolean] ||
[elementName isEqualToString:kCMISAtomEntryPropertyUri] ||
[elementName isEqualToString:kCMISAtomEntryPropertyHtml] ||
[elementName isEqualToString:kCMISAtomEntryPropertyDecimal]) {
// add the property to the properties dictionary
self.currentPropertyData.values = self.propertyValues;
self.propertyValues = nil;
[self.currentObjectProperties addProperty:self.currentPropertyData];
self.currentPropertyData = nil;
} else if ([elementName isEqualToString:kCMISCoreProperties]) {
// Finished parsing Properties & its ExtensionData
[self saveCurrentExtensionsAndPushPreviousExtensionData];
} else if ([elementName isEqualToString:kCMISCoreRendition]) {
if (self.currentRenditions == nil) {
self.currentRenditions = [[NSMutableArray alloc] init];
}
[self.currentRenditions addObject:self.currentRendition];
self.currentRendition = nil;
}
}
// the relationship element has ended
if ([elementName isEqualToString:kCMISCoreRelationship]) {
self.parsingRelationship = NO;
}
} else if ([namespaceURI isEqualToString:kCMISNamespaceAtom]) {
if ( [elementName isEqualToString:kCMISAtomEntry]) {
// set the properties on the objectData object
self.objectData.properties = self.currentObjectProperties;
// set the link relations on the objectData object
self.objectData.linkRelations = [[CMISLinkRelations alloc] initWithLinkRelationSet:[self.currentLinkRelations copy]];
// set the renditions on the objectData object
self.objectData.renditions = self.currentRenditions;
// set the objectData identifier
CMISPropertyData *objectId = [self.currentObjectProperties.propertiesDictionary objectForKey:kCMISPropertyObjectId];
self.objectData.identifier = [objectId firstValue];
// set the objectData baseType
CMISPropertyData *baseTypeProperty = [self.currentObjectProperties.propertiesDictionary objectForKey:kCMISPropertyBaseTypeId];
NSString *baseType = [baseTypeProperty firstValue];
if ([baseType isEqualToString:kCMISPropertyObjectTypeIdValueDocument]) {
self.objectData.baseType = CMISBaseTypeDocument;
} else if ([baseType isEqualToString:kCMISPropertyObjectTypeIdValueFolder]) {
self.objectData.baseType = CMISBaseTypeFolder;
}
// set the extensionData
[self saveCurrentExtensionsAndPushPreviousExtensionData];
self.currentObjectProperties = nil;
if (self.parentDelegate) {
if ([self.parentDelegate respondsToSelector:@selector(cmisAtomEntryParser:didFinishParsingCMISObjectData:)]) {
// Message the parent delegate the parsed ObjectData
[self.parentDelegate performSelector:@selector(cmisAtomEntryParser:didFinishParsingCMISObjectData:)
withObject:self withObject:self.objectData];
}
// Resetting our parent as the delegate since we're done
parser.delegate = self.parentDelegate;
self.parentDelegate = nil;
}
}
} else if ([namespaceURI isEqualToString:kCMISNamespaceApp]) {
// Nothing to do in this namespace
} else {
// TODO other namespaces?
}
self.string = nil;
}
#pragma mark -
#pragma mark CMISAllowableActionsParserDelegate Methods
- (void)allowableActionsParser:(CMISAllowableActionsParser *)parser didFinishParsingAllowableActions:(CMISAllowableActions *)allowableActions
{
self.objectData.allowableActions = allowableActions;
}
@end