diff --git a/BatchImportOperation.m b/BatchImportOperation.m index 982ca3b..16b1c8e 100644 --- a/BatchImportOperation.m +++ b/BatchImportOperation.m @@ -15,6 +15,7 @@ #import "AppDelegate.h" #import "MOC.h" #import "NSString+magic.h" +#import "SpiresXMLArticle.h" @implementation BatchImportOperation { @@ -53,93 +54,30 @@ -(NSString*)description } #pragma mark setters from XML --(NSString*)valueForKey:(NSString*)key inXMLElement:(NSXMLElement*)element -{ - NSArray*a=[element elementsForName:key]; - if(a==nil||[a count]==0)return nil; - NSString*s=[a[0] stringValue]; - if(!s || [s isEqualToString:@""]) - return nil; - return s; -} --(void)setIntToArticle:(Article*)a forKey:(NSString*)key inXMLElement:(NSXMLElement*)e -{ - NSString* s=[self valueForKey:key inXMLElement:e]; - if(s) - [a setValue:@([s intValue]) forKey:key]; -} --(void)setStringToArticle:(Article*)a forKey:(NSString*)key inXMLElement:(NSXMLElement*)e -{ - NSString* s=[self valueForKey:key inXMLElement:e]; - if(s){ - // s=[s stringByExpandingAmpersandEscapes]; - [a setValue:s forKey:key]; - } -} --(void)setStringToArticle:(Article*)a forKey:(NSString*)key inXMLElement:(NSXMLElement*)e ofKey:(NSString*)xmlKey -{ - NSString* s=[self valueForKey:xmlKey inXMLElement:e]; - if(s) - [a setValue:s forKey:key]; -} --(void)setJournalToArticle:(Article*)a inXMLElement:(NSXMLElement*)e -{ - if(a.journal)return; - NSArray* x=[e elementsForName:@"journal"]; - if(!x || [x count]==0) return; - NSXMLElement* element=x[0]; - NSString *name=[self valueForKey:@"name" inXMLElement:element]; - if(!name || [name isEqualToString:@""])return; - JournalEntry*j=[JournalEntry journalEntryWithName:name - Volume:[self valueForKey:@"volume" inXMLElement:element] - Year:[[self valueForKey:@"year" inXMLElement:element] intValue] - Page:[self valueForKey:@"page" inXMLElement:element] - inMOC:[a managedObjectContext]]; - a.journal=j; -} --(void)setDateToArticle:(Article*)a inXMLElement:(NSXMLElement*)e -{ - NSString*dateString=[self valueForKey:@"date" inXMLElement:e]; - if(!dateString || [dateString length]!=8)return; - NSString*year=[dateString substringToIndex:4]; - NSString*month=[dateString substringWithRange:NSMakeRange(4,2)]; - NSDate*date=[NSDate dateWithString:[NSString stringWithFormat:@"%@-%@-01 00:00:00 +0000",year,month]]; - a.date=date; -} --(void)populatePropertiesOfArticle:(Article*)o fromXML:(NSXMLElement*)element -{ - NSString*eprint=[self valueForKey:@"eprint" inXMLElement:element]; - NSString*spiresKey=[self valueForKey:@"spires_key" inXMLElement:element]; - NSString*title=[self valueForKey:@"title" inXMLElement:element]; - - o.spiresKey=@([spiresKey integerValue]); - o.eprint=eprint; - o.title=title; - - NSError*error=nil; - NSArray*a=[element nodesForXPath:@"authaffgrp/author" error:&error]; - NSMutableArray* array=[NSMutableArray array]; - for(NSXMLElement*e in a){ - [array addObject:[e stringValue]]; - } - +-(void)populatePropertiesOfArticle:(Article*)o fromProtoArticle:(ProtoArticle*)element +{ + o.spiresKey=@([element.spiresKey integerValue]); + o.inspireKey=@([element.inspireKey integerValue]); + o.eprint=element.eprint; + o.title=element.title; // Here I'm cheating: -setAuthorNames: puts the collaboration name in the author list, // so "collaboration" needs to be set up before that - [self setStringToArticle:o forKey:@"collaboration" inXMLElement:element]; - [o setAuthorNames:array]; - - - [self setStringToArticle:o forKey:@"doi" inXMLElement:element]; - [self setStringToArticle:o forKey:@"abstract" inXMLElement:element]; - [self setStringToArticle:o forKey:@"comments" inXMLElement:element]; - [self setStringToArticle:o forKey:@"memo" inXMLElement:element]; - [self setStringToArticle:o forKey:@"spicite" inXMLElement:element]; - [self setIntToArticle:o forKey:@"citecount" inXMLElement:element]; - [self setIntToArticle:o forKey:@"version" inXMLElement:element]; - [self setIntToArticle:o forKey:@"pages" inXMLElement:element]; - [self setJournalToArticle:o inXMLElement:element]; - [self setDateToArticle:o inXMLElement:element]; + o.collaboration=element.collaboration; + [o setAuthorNames:element.authors]; + o.doi=element.doi; + o.abstract=element.abstract; + o.comments=element.comments; + o.citecount=element.citecount; + o.pages=element.pages; + o.date=element.date; + if(!(o.journal) && element.journalTitle){ + o.journal=[JournalEntry journalEntryWithName:element.journalTitle + Volume:element.journalVolume + Year:[element.journalYear intValue] + Page:element.journalPage + inMOC:[o managedObjectContext]]; + } if(o.abstract){ NSString*abstract=o.abstract; @@ -149,21 +87,17 @@ -(void)populatePropertiesOfArticle:(Article*)o fromXML:(NSXMLElement*)element o.abstract=abstract; } - NSString*inspireKey=[self valueForKey:@"inspire_key" inXMLElement:element]; - if(inspireKey){ - o.inspireKey=@([inspireKey integerValue]); - } } #pragma mark Main Logic --(void)treatElements:(NSMutableArray*)a withXMLKey:(NSString*)xmlKey andKey:(NSString*)key +-(void)treatElements:(NSMutableArray*)a withKey:(NSString*)key { if([a count]==0) return ; NSMutableDictionary*dict=[NSMutableDictionary dictionary]; - for(NSXMLElement*e in a){ - NSString*v=[self valueForKey:xmlKey inXMLElement:e]; + for(ProtoArticle*e in a){ + NSString*v=[e valueForKey:key]; dict[v] = e; } @@ -179,7 +113,6 @@ -(void)treatElements:(NSMutableArray*)a withXMLKey:(NSString*)xmlKey andKey:(NSS NSError*error=nil; NSArray*datas=[secondMOC executeFetchRequest:req error:&error]; - int i=0,j=0; for(ArticleData*data in datas){ if(!data.article){ NSLog(@"inconsistency! stray ArticleData found and removed: %@",data); @@ -190,18 +123,16 @@ -(void)treatElements:(NSMutableArray*)a withXMLKey:(NSString*)xmlKey andKey:(NSS if([v isKindOfClass:[NSNumber class]]){ v=[(NSNumber*)v stringValue]; } - NSXMLElement*e=dict[v]; - [self populatePropertiesOfArticle:data.article fromXML:e]; + ProtoArticle*e=dict[v]; + [self populatePropertiesOfArticle:data.article fromProtoArticle:e]; [generated addObject:data.article]; [a removeObject:e]; - i++; } NSEntityDescription*articleEntity=[NSEntityDescription entityForName:@"Article" inManagedObjectContext:secondMOC]; - for(NSXMLElement*e in a){ + for(ProtoArticle*e in a){ Article*article=(Article*)[[NSManagedObject alloc] initWithEntity:articleEntity insertIntoManagedObjectContext:secondMOC]; - [self populatePropertiesOfArticle:article fromXML:e]; + [self populatePropertiesOfArticle:article fromProtoArticle:e]; [generated addObject:article]; - j++; } } -(void)batchAddEntriesOfSPIRES:(NSArray*)a @@ -210,25 +141,22 @@ -(void)batchAddEntriesOfSPIRES:(NSArray*)a NSMutableArray*lookForSpiresKey=[NSMutableArray array]; NSMutableArray*lookForDOI=[NSMutableArray array]; NSMutableArray*lookForTitle=[NSMutableArray array]; - for(NSXMLElement*element in a){ - NSString*eprint=[self valueForKey:@"eprint" inXMLElement:element]; - NSString*spiresKey=[self valueForKey:@"spires_key" inXMLElement:element]; - NSString*doi=[self valueForKey:@"doi" inXMLElement:element]; - NSString*title=[self valueForKey:@"title" inXMLElement:element]; - if(eprint){ + for(ProtoArticle*element in a){ + if(element.eprint){ [lookForEprint addObject:element]; - }else if(spiresKey){ + }else if(element.spiresKey){ [lookForSpiresKey addObject:element]; - }else if(doi){ + }else if(element.doi){ [lookForDOI addObject:element]; - }else if(title){ + }else if(element.title){ [lookForTitle addObject:element]; } } - [self treatElements:lookForEprint withXMLKey:@"eprint" andKey:@"eprint"]; - [self treatElements:lookForSpiresKey withXMLKey:@"spires_key" andKey:@"spiresKey"]; - [self treatElements:lookForTitle withXMLKey:@"title" andKey:@"title"]; + [self treatElements:lookForEprint withKey:@"eprint"]; + [self treatElements:lookForSpiresKey withKey:@"spiresKey"]; + [self treatElements:lookForDOI withKey:@"doi"]; + [self treatElements:lookForTitle withKey:@"title"]; // you shouldn't mix dispatch to the main thread and performSelectorOnMainThread, // they're not guaranteed to be serialized! @@ -267,9 +195,7 @@ -(void)main { [secondMOC performBlockAndWait:^{ - NSXMLDocument*doc=[[NSXMLDocument alloc] initWithData:xmlData options:NSXMLNodeOptionsNone error:NULL]; - NSXMLElement* root=[doc rootElement]; - NSArray*elements=[root elementsForName:@"document"]; + NSArray*elements=[SpiresXMLArticle articlesFromXMLData:xmlData]; NSLog(@"spires returned %d entries",(int)[elements count]); [self batchAddEntriesOfSPIRES:elements]; [secondMOC save:NULL]; diff --git a/ProtoArticle.h b/ProtoArticle.h new file mode 100644 index 0000000..943ae4c --- /dev/null +++ b/ProtoArticle.h @@ -0,0 +1,29 @@ +// +// ProtoArticle.h +// inspire +// +// Created by Yuji on 2015/08/09. +// +// + +#import + +@interface ProtoArticle : NSObject +@property (readonly) NSString*title; +@property (readonly) NSString*inspireKey; +@property (readonly) NSString*spiresKey; +@property (readonly) NSString*eprint; +@property (readonly) NSArray*authors; +@property (readonly) NSString*abstract; +@property (readonly) NSString*collaboration; +@property (readonly) NSNumber*pages; +@property (readonly) NSNumber*citecount; +@property (readonly) NSDate*date; +@property (readonly) NSDictionary*publicationInfo; +@property (readonly) NSString*doi; +@property (readonly) NSString*comments; +@property (readonly) NSString*journalTitle; +@property (readonly) NSString*journalVolume; +@property (readonly) NSString*journalPage; +@property (readonly) NSNumber*journalYear; +@end diff --git a/ProtoArticle.m b/ProtoArticle.m new file mode 100644 index 0000000..6e9056d --- /dev/null +++ b/ProtoArticle.m @@ -0,0 +1,13 @@ +// +// ProtoArticle.m +// inspire +// +// Created by Yuji on 2015/08/09. +// +// + +#import "ProtoArticle.h" + +@implementation ProtoArticle + +@end diff --git a/SpiresAppDelegate_actions.m b/SpiresAppDelegate_actions.m index 5a8d161..267d4e6 100644 --- a/SpiresAppDelegate_actions.m +++ b/SpiresAppDelegate_actions.m @@ -57,7 +57,7 @@ -(IBAction)installSafariExtension:(id)sender; defaultButton:@"OK" alternateButton:nil otherButton:nil - informativeTextWithFormat:nil]; + informativeTextWithFormat:@""]; [alert runModal]; return; } diff --git a/SpiresXMLArticle.h b/SpiresXMLArticle.h new file mode 100644 index 0000000..4ebf5e1 --- /dev/null +++ b/SpiresXMLArticle.h @@ -0,0 +1,14 @@ +// +// SpiresXMLArticle.h +// inspire +// +// Created by Yuji on 2015/08/09. +// +// + +#import "ProtoArticle.h" + +@interface SpiresXMLArticle : ProtoArticle ++(NSArray*)articlesFromXMLData:(NSData*)data; +-(instancetype)initWithXMLElement:(NSXMLElement*)node; +@end diff --git a/SpiresXMLArticle.m b/SpiresXMLArticle.m new file mode 100644 index 0000000..5d59530 --- /dev/null +++ b/SpiresXMLArticle.m @@ -0,0 +1,136 @@ +// +// SpiresXMLArticle.m +// inspire +// +// Created by Yuji on 2015/08/09. +// +// + +#import "SpiresXMLArticle.h" + +@implementation SpiresXMLArticle +{ + NSXMLElement*element; + NSXMLElement*journal; +} ++(NSArray*)articlesFromXMLData:(NSData*)data +{ + NSXMLDocument*doc=[[NSXMLDocument alloc] initWithData:data options:NSXMLNodeOptionsNone error:NULL]; + NSXMLElement* root=[doc rootElement]; + NSArray*elements=[root elementsForName:@"document"]; + NSMutableArray*result=[NSMutableArray array]; + for(NSXMLElement*e in elements){ + [result addObject:[[SpiresXMLArticle alloc] initWithXMLElement:e]]; + } + return result; +} +-(instancetype)initWithXMLElement:(NSXMLElement*)node +{ + self=[super init]; + element=node; + return self; +} +-(NSXMLElement*)journal +{ + if(!journal){ + NSArray* x=[element elementsForName:@"journal"]; + if(!x || [x count]==0) return nil; + journal=x[0]; + } + return journal; +} +-(NSString*)stringForKey:(NSString*)key inXMLElement:(NSXMLElement*)xmlElement +{ + NSArray*a=[xmlElement elementsForName:key]; + if(a==nil||[a count]==0)return nil; + NSString*s=[a[0] stringValue]; + if(!s || [s isEqualToString:@""]) + return nil; + return s; +} +-(NSString*)stringForKey:(NSString*)key +{ + return [self stringForKey:key inXMLElement:element]; +} +-(NSString*)journalTitle +{ + if(!self.journal) return nil; + return [self stringForKey:@"name" inXMLElement:self.journal]; +} +-(NSString*)journalPage +{ + if(!self.journal) return nil; + return [self stringForKey:@"page" inXMLElement:self.journal]; +} +-(NSString*)journalVolume +{ + if(!self.journal) return nil; + return [self stringForKey:@"volume" inXMLElement:self.journal]; +} +-(NSNumber*)journalYear +{ + if(!self.journal) return nil; + return @([[self stringForKey:@"year" inXMLElement:self.journal] integerValue]); +} + +-(NSString*)eprint +{ + return [self stringForKey:@"eprint"]; +} +-(NSString*)spiresKey +{ + return [self stringForKey:@"spires_key"]; +} +-(NSString*)inspireKey +{ + return [self stringForKey:@"inspire_key"]; +} +-(NSString*)doi +{ + return [self stringForKey:@"doi"]; +} +-(NSString*)title +{ + return [self stringForKey:@"title"]; +} +-(NSString*)collaboration +{ + return [self stringForKey:@"collaboration"]; +} +-(NSString*)abstract +{ + return [self stringForKey:@"abstract"]; +} +-(NSString*)comments +{ + return [self stringForKey:@"comments"]; +} +-(NSNumber*)citecount +{ + return @(0); +} +-(NSNumber*)pages +{ + return @([[self stringForKey:@"pages"] integerValue]); +} +-(NSDate*)date +{ + NSString*dateString=[self stringForKey:@"date"]; + if(!dateString || [dateString length]!=8)return nil; + NSString*year=[dateString substringToIndex:4]; + NSString*month=[dateString substringWithRange:NSMakeRange(4,2)]; + NSDate*date=[NSDate dateWithString:[NSString stringWithFormat:@"%@-%@-01 00:00:00 +0000",year,month]]; + return date; +} +-(NSArray*)authors +{ + NSError*error=nil; + NSArray*a=[element nodesForXPath:@"authaffgrp/author" error:&error]; + NSMutableArray* array=[NSMutableArray array]; + + for(NSXMLElement*e in a){ + [array addObject:[e stringValue]]; + } + return array; +} +@end diff --git a/inspire.xcodeproj/project.pbxproj b/inspire.xcodeproj/project.pbxproj index 9d6e604..a41aae8 100644 --- a/inspire.xcodeproj/project.pbxproj +++ b/inspire.xcodeproj/project.pbxproj @@ -23,6 +23,8 @@ 331E6EFB0FFE83CB00F07C9A /* SpiresQueryDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 331E6EFA0FFE83CB00F07C9A /* SpiresQueryDownloader.m */; }; 331FD3310F36B11800C16F73 /* MainTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 331FD3300F36B11800C16F73 /* MainTableViewController.m */; }; 33255AAB0F3131F500538063 /* Acknowledgments.html in Resources */ = {isa = PBXBuildFile; fileRef = 33255AAA0F3131F500538063 /* Acknowledgments.html */; }; + 332733C31B76EF8F0072BCFE /* ProtoArticle.m in Sources */ = {isa = PBXBuildFile; fileRef = 332733C21B76EF8F0072BCFE /* ProtoArticle.m */; }; + 332733C61B76EFF90072BCFE /* SpiresXMLArticle.m in Sources */ = {isa = PBXBuildFile; fileRef = 332733C51B76EFF90072BCFE /* SpiresXMLArticle.m */; }; 332824940F560DE800AA6E00 /* dsa_pub.pem in Resources */ = {isa = PBXBuildFile; fileRef = 332824930F560DE800AA6E00 /* dsa_pub.pem */; }; 332B9B290FF9E34400353564 /* DirWatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 332B9B280FF9E34400353564 /* DirWatcher.m */; }; 332BD63610CECF500032EF88 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 332BD63510CECF500032EF88 /* AppDelegate.m */; }; @@ -184,6 +186,10 @@ 33202EE010D9D8EA00EDB5A8 /* Migrator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Migrator.h; sourceTree = ""; }; 33202EE110D9D8EA00EDB5A8 /* Migrator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Migrator.m; sourceTree = ""; }; 33255AAA0F3131F500538063 /* Acknowledgments.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = Acknowledgments.html; sourceTree = ""; }; + 332733C11B76EF8F0072BCFE /* ProtoArticle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProtoArticle.h; sourceTree = ""; }; + 332733C21B76EF8F0072BCFE /* ProtoArticle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ProtoArticle.m; sourceTree = ""; }; + 332733C41B76EFF90072BCFE /* SpiresXMLArticle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpiresXMLArticle.h; sourceTree = ""; }; + 332733C51B76EFF90072BCFE /* SpiresXMLArticle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SpiresXMLArticle.m; sourceTree = ""; }; 332824930F560DE800AA6E00 /* dsa_pub.pem */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = dsa_pub.pem; sourceTree = ""; }; 332B9B270FF9E34400353564 /* DirWatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DirWatcher.h; sourceTree = ""; }; 332B9B280FF9E34400353564 /* DirWatcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DirWatcher.m; sourceTree = ""; }; @@ -803,6 +809,10 @@ 7756732906782D8800D1FEB8 /* Models */ = { isa = PBXGroup; children = ( + 332733C11B76EF8F0072BCFE /* ProtoArticle.h */, + 332733C21B76EF8F0072BCFE /* ProtoArticle.m */, + 332733C41B76EFF90072BCFE /* SpiresXMLArticle.h */, + 332733C51B76EFF90072BCFE /* SpiresXMLArticle.m */, 3304B8A10F92CEFB002156A9 /* ArticleLists */, 330207AA0F5990210067714C /* MOC.h */, 330207AB0F5990210067714C /* MOC.m */, @@ -971,6 +981,7 @@ 338AC4780F3691B40011414C /* ProgressIndicatorController.m in Sources */, 331FD3310F36B11800C16F73 /* MainTableViewController.m in Sources */, 33C7A4390F3D0EA600F3874C /* SecureDownloader.m in Sources */, + 332733C31B76EF8F0072BCFE /* ProtoArticle.m in Sources */, 33CC06E80F3E48B8005B25F8 /* DumbOperation.m in Sources */, 33CC07050F3E4E73005B25F8 /* JournalPDFDownloadOperation.m in Sources */, 33CC07D80F3E5E57005B25F8 /* NSFileManager+TemporaryFileName.m in Sources */, @@ -984,6 +995,7 @@ 339579410F3ECA3A0036364A /* LoadAbstractDOIOperation.m in Sources */, 339579770F3ECE670036364A /* ArxivMetadataFetchOperation.m in Sources */, 337A3E970F3FA7680008906A /* DeferredPDFOpenOperation.m in Sources */, + 332733C61B76EFF90072BCFE /* SpiresXMLArticle.m in Sources */, 331C8F100F4CC84300779F05 /* NSString+magic.m in Sources */, 333C79070F5230780075267A /* NSURL+libraryProxy.m in Sources */, 330207AC0F5990210067714C /* MOC.m in Sources */,