Revision: 22016 http://sourceforge.net/p/bibdesk/svn/22016 Author: hofman Date: 2018-02-23 15:44:34 +0000 (Fri, 23 Feb 2018) Log Message: ----------- Implement some generic part of web parser handlers in abstract superclasses, to void repeating the same thing (mainly error handling), and making sure the delegate methods are properly called
Modified Paths: -------------- trunk/bibdesk/BDSKArxivParser.m trunk/bibdesk/BDSKAsynchronousWebParser.h trunk/bibdesk/BDSKAsynchronousWebParser.m trunk/bibdesk/BDSKBibTeXWebParser.m trunk/bibdesk/BDSKCOinSParser.m trunk/bibdesk/BDSKHCiteParser.m trunk/bibdesk/BDSKHubmedParser.m trunk/bibdesk/BDSKIACRParser.m trunk/bibdesk/BDSKIEEEXploreParser.m trunk/bibdesk/BDSKInspireParser.m trunk/bibdesk/BDSKJSTORWebParser.m trunk/bibdesk/BDSKLinkedBibTeXParser.m trunk/bibdesk/BDSKMASParser.m trunk/bibdesk/BDSKMathSciNetParser.m trunk/bibdesk/BDSKNumdamParser.m trunk/bibdesk/BDSKProjectEuclidParser.m trunk/bibdesk/BDSKWebParser.h trunk/bibdesk/BDSKWebParser.m trunk/bibdesk/BDSKZentralblattParser.m trunk/bibdesk/English.lproj/Localizable.strings trunk/bibdesk/French.lproj/Localizable.strings trunk/bibdesk/German.lproj/Localizable.strings Modified: trunk/bibdesk/BDSKArxivParser.m =================================================================== --- trunk/bibdesk/BDSKArxivParser.m 2018-02-23 07:30:46 UTC (rev 22015) +++ trunk/bibdesk/BDSKArxivParser.m 2018-02-23 15:44:34 UTC (rev 22016) @@ -39,7 +39,6 @@ #import "BDSKArxivParser.h" #import "BibItem.h" #import "BDSKLinkedFile.h" -#import "NSError_BDSKExtensions.h" #import "NSXMLNode_BDSKExtensions.h" #import <AGRegex/AGRegex.h> @@ -68,7 +67,7 @@ // A potential enhancement would be to recognize documents that are index lists of citations // and follow links two levels deep to get bibitems from each citation in the list. -- (void)start { +- (NSArray *)itemsReturningError:(NSError **)outError { NSURL *url = [self URL]; @@ -110,13 +109,11 @@ AGRegex *journalRegex3 = [AGRegex regexWithPattern:@"(.+[^0-9])([0-9]+):(.*),([0-9]{4})" options:AGRegexMultiline]; - NSError *searchError = nil; - // fetch the arxiv search results NSArray *arxivSearchResults = nil; NSXMLElement *rootElement = [[self xmlDocument] rootElement]; - arxivSearchResults = [rootElement nodesForXPath:arxivSearchResultNodePath error:&searchError]; + arxivSearchResults = [rootElement nodesForXPath:arxivSearchResultNodePath error:outError]; NSMutableArray *items = [NSMutableArray arrayWithCapacity:0]; @@ -275,13 +272,8 @@ [item release]; } - - if (0 == [items count] && searchError == nil) { - searchError = [NSError mutableLocalErrorWithCode:kBDSKWebParserFailed localizedDescription:NSLocalizedString(@"No search results found", @"Web parser error")]; - [searchError setValue:NSLocalizedString(@"Unable to parse this page. Please report this to BibDesk's developers and provide the URL.", @"Web parser error") forKey:NSLocalizedRecoverySuggestionErrorKey]; - } - [self didFinishStartingFindingItems:items withSuccess:[items count] > 0 error:searchError]; + return items; } Modified: trunk/bibdesk/BDSKAsynchronousWebParser.h =================================================================== --- trunk/bibdesk/BDSKAsynchronousWebParser.h 2018-02-23 07:30:46 UTC (rev 22015) +++ trunk/bibdesk/BDSKAsynchronousWebParser.h 2018-02-23 15:44:34 UTC (rev 22016) @@ -48,33 +48,14 @@ #pragma mark - @interface BDSKAsynchronousWebParser : BDSKWebParser <BDSKCitationDownloadDelegate> { - BOOL finishedAddingDownloads; NSMutableArray *downloads; } -// subclasses should set this when all downloads are added -@property (nonatomic) BOOL finishedAddingDownloads; -// whether the parser can finish, checks finishedAddingDownloads and no active downloads -@property (nonatomic, readonly) BOOL canFinish; - -// starts the download immediately after adding -- (void)addDownload:(BDSKCitationDownload *)download; -// subclasses should call this at the end of the download callback -- (void)removeDownload:(BDSKCitationDownload *)download; - -// start should finish when it ends without downloads - -// don't call super -// subclasses should remove the download -// make sure subclasses finish when there are no further downloads -- (void)downloadDidFinish:(BDSKCitationDownload *)download; - -// convenience method to add a new download +// subclasses can add downloads in -itemsReturningError: - (void)addDownloadWithRequest:(NSURLRequest *)request contextInfo:(id)contextInfo; -// convenience method to remove the download and call the various delegate methods if needed -// subclasses can use this at the end of downloadDidFinish: instead of calling the delegate methods -- (void)didFinishDownload:(BDSKCitationDownload *)download findingItems:(NSArray *)items withSuccess:(BOOL)success error:(NSError *)error; +// main method for subclasses to implement, together with -itemsReturningError: +- (NSArray *)itemsFromDownload:(BDSKCitationDownload *)download error:(NSError **)outError; @end Modified: trunk/bibdesk/BDSKAsynchronousWebParser.m =================================================================== --- trunk/bibdesk/BDSKAsynchronousWebParser.m 2018-02-23 07:30:46 UTC (rev 22015) +++ trunk/bibdesk/BDSKAsynchronousWebParser.m 2018-02-23 15:44:34 UTC (rev 22016) @@ -37,29 +37,17 @@ */ #import "BDSKAsynchronousWebParser.h" +#import "BibItem.h" +#import "NSError_BDSKExtensions.h" @implementation BDSKAsynchronousWebParser -@synthesize finishedAddingDownloads; -@dynamic canFinish; - - (void)dealloc { BDSKDESTROY(downloads); [super dealloc]; } -- (void)addDownload:(BDSKCitationDownload *)download { - if (downloads == nil) - downloads = [[NSMutableArray alloc] init]; - [downloads addObject:download]; - [download start]; -} - -- (void)removeDownload:(BDSKCitationDownload *)download { - [downloads removeObject:download]; -} - - (void)cancel { [super cancel]; [downloads makeObjectsPerformSelector:@selector(cancel)]; @@ -67,37 +55,64 @@ } - (BOOL)canFinish { - return [self finishedAddingDownloads] && [downloads count] == 0; + return [self finishedStarting] && [downloads count] == 0; } +- (BOOL)succeededWithItems:(NSArray *)items { + return [items count] > 0 || downloads != nil; +} + - (void)downloadDidFinish:(BDSKCitationDownload *)download { - [self didFinishDownload:download findingItems:nil withSuccess:YES error:nil]; + NSArray *items = nil; + NSError *error = [download error]; + + if ([download failed] == NO) + items = [self itemsFromDownload:download error:&error]; + + if ([items count] == 0) { + // display a fake item in the table so the user knows one of the items failed to parse, but still gets the rest of the data + NSString *errMsg = [error localizedDescription]; + if (errMsg == nil) + errMsg = NSLocalizedString(@"Unable to parse as BibTeX", @"Web parser error"); + NSMutableDictionary *pubFields = [NSMutableDictionary dictionaryWithObjectsAndKeys:errMsg, BDSKTitleString, nil]; + NSString *string = [download string]; + if ([download URL]) + [pubFields setObject:[[download URL] absoluteString] forKey:BDSKUrlString]; + if ([error localizedRecoverySuggestion]) + [pubFields setObject:[error localizedRecoverySuggestion] forKey:BDSKAbstractString]; + if (string) + [pubFields setObject:string forKey:BDSKAnnoteString]; + BibItem *errorItem = [[BibItem alloc] initWithType:BDSKMiscString citeKey:nil pubFields:pubFields isNew:YES]; + items = [NSArray arrayWithObjects:errorItem, nil]; + [errorItem release]; + } + + if ([items count] > 0) + [[self delegate] webParser:self didFindItems:items]; + + [downloads removeObject:download]; + + if ([self canFinish]) + [[self delegate] webParser:self didFinishWithSuccess:YES error:nil]; } - (void)addDownloadWithRequest:(NSURLRequest *)request contextInfo:(id)contextInfo { BDSKCitationDownload *download = [[BDSKCitationDownload alloc] initWithRequest:request delegate:self]; + if (contextInfo) [download setContextInfo:contextInfo]; - [self addDownload:download]; + + if (downloads == nil) + downloads = [[NSMutableArray alloc] init]; + [downloads addObject:download]; + + [download start]; + [download release]; } -- (void)didFinishStartingFindingItems:(NSArray *)items withSuccess:(BOOL)success error:(NSError *)error { - if ([items count] > 0) - [[self delegate] webParser:self didFindItems:items]; - [self setFinishedAddingDownloads:YES]; - if ([self canFinish]) - [[self delegate] webParser:self didFinishWithSuccess:success error:error]; -} +- (NSArray *)itemsFromDownload:(BDSKCitationDownload *)download error:(NSError **)outError { return nil; } -- (void)didFinishDownload:(BDSKCitationDownload *)download findingItems:(NSArray *)items withSuccess:(BOOL)success error:(NSError *)error { - if ([items count] > 0) - [[self delegate] webParser:self didFindItems:items]; - [self removeDownload:download]; - if ([self canFinish]) - [[self delegate] webParser:self didFinishWithSuccess:success error:error]; -} - @end #pragma mark - Modified: trunk/bibdesk/BDSKBibTeXWebParser.m =================================================================== --- trunk/bibdesk/BDSKBibTeXWebParser.m 2018-02-23 07:30:46 UTC (rev 22015) +++ trunk/bibdesk/BDSKBibTeXWebParser.m 2018-02-23 15:44:34 UTC (rev 22016) @@ -39,7 +39,6 @@ #import "BDSKBibTeXWebParser.h" #import "BDSKBibTeXParser.h" #import "BibItem.h" -#import "NSError_BDSKExtensions.h" #import "NSXMLNode_BDSKExtensions.h" #import <AGRegex/AGRegex.h> @@ -69,12 +68,12 @@ } -- (void)start { +- (NSArray *)itemsReturningError:(NSError **)outError { NSMutableArray *items = [NSMutableArray array]; NSString *mayContainBibtexXPath = @"./body//*/text()[contains(.,'@')]/.."; NSError *error = nil; - NSArray *nodes = [[xmlDocument rootElement] nodesForXPath:mayContainBibtexXPath error:&error]; + NSArray *nodes = [[xmlDocument rootElement] nodesForXPath:mayContainBibtexXPath error:outError]; if ([nodes count] > 0) { // get a list of all things that might be the beginnings of a BibTeX item @@ -95,7 +94,7 @@ } } - [self didFinishStartingFindingItems:items withSuccess:[items count] > 0 error:error]; + return items; } + (NSDictionary *)parserInfo { Modified: trunk/bibdesk/BDSKCOinSParser.m =================================================================== --- trunk/bibdesk/BDSKCOinSParser.m 2018-02-23 07:30:46 UTC (rev 22015) +++ trunk/bibdesk/BDSKCOinSParser.m 2018-02-23 15:44:34 UTC (rev 22016) @@ -42,7 +42,6 @@ #import "NSXMLNode_BDSKExtensions.h" #import "BDSKLinkedFile.h" #import "NSString_BDSKExtensions.h" -#import "NSError_BDSKExtensions.h" /* The COinS or Z3988 format is a microformat which is embedded in web pages to include bibliographic information there. @@ -311,35 +310,23 @@ } // Process the document. -- (void)start { +- (NSArray *)itemsReturningError:(NSError **)outError { NSError *error; - NSArray *nodes = [[[self xmlDocument] rootElement] nodesForXPath:@".//span[@class='Z3988']" error:&error]; + NSArray *nodes = [[[self xmlDocument] rootElement] nodesForXPath:@".//span[@class='Z3988']" error:outError]; - NSMutableArray *results = nil; + NSMutableArray *items = [NSMutableArray arrayWithCapacity:[nodes count]]; - if (0 == [nodes count]) { - // bail out with an XML error if the Xpath query fails - if (error == nil) { - error = [NSError mutableLocalErrorWithCode:kBDSKWebParserFailed localizedDescription:NSLocalizedString(@"No search results found", @"Web parser error")]; - [error setValue:NSLocalizedString(@"Unable to parse this page. Please report this to BibDesk's developers and provide the URL.", @"Web parser error") forKey:NSLocalizedRecoverySuggestionErrorKey]; - } - - } else { - - results = [NSMutableArray arrayWithCapacity:[nodes count]]; - - for (NSXMLNode *node in nodes) { - NSString *title; - BibItem *bibItem; - if ([node kind] == NSXMLElementKind && - (title = [[(NSXMLElement *)node attributeForName:@"title"] XMLString]) && - (bibItem = [BDSKCOinSParser parseCOinSString:title])) - [results addObject:bibItem]; - } + for (NSXMLNode *node in nodes) { + NSString *title; + BibItem *bibItem; + if ([node kind] == NSXMLElementKind && + (title = [[(NSXMLElement *)node attributeForName:@"title"] XMLString]) && + (bibItem = [BDSKCOinSParser parseCOinSString:title])) + [items addObject:bibItem]; } - [self didFinishStartingFindingItems:results withSuccess:[results count] != 0 error:error]; + return items; } // Array with feature description dictionary for the COinS microformat. Modified: trunk/bibdesk/BDSKHCiteParser.m =================================================================== --- trunk/bibdesk/BDSKHCiteParser.m 2018-02-23 07:30:46 UTC (rev 22015) +++ trunk/bibdesk/BDSKHCiteParser.m 2018-02-23 15:44:34 UTC (rev 22016) @@ -40,7 +40,6 @@ #import "BibItem.h" #import "BDSKTypeManager.h" #import "NSXMLNode_BDSKExtensions.h" -#import "NSError_BDSKExtensions.h" @interface BDSKHCiteParser (Private) @@ -60,15 +59,13 @@ return [[[xmlDocument rootElement] nodesForXPath:containsCitationPath error:&error] count] > 0; } -- (void)start { +- (NSArray *)itemsReturningError:(NSError **)outError { NSMutableArray *items = [NSMutableArray arrayWithCapacity:0]; NSString *containsCitationPath = @"./body//*[contains(concat(' ', normalize-space(@class), ' '),' hcite ')]"; - NSError *error = nil; - - NSArray *mainNodes = [[[self xmlDocument] rootElement] nodesForXPath:containsCitationPath error:&error]; + NSArray *mainNodes = [[[self xmlDocument] rootElement] nodesForXPath:containsCitationPath error:outError]; for (NSXMLNode *obj in mainNodes) { @@ -85,13 +82,8 @@ isNew:YES] autorelease]; [items addObject:item]; } - - if ([items count] == 0 && error == nil) { - error = [NSError mutableLocalErrorWithCode:kBDSKWebParserFailed localizedDescription:NSLocalizedString(@"No search results found", @"Web parser error")]; - [error setValue:NSLocalizedString(@"Unable to parse this page. Please report this to BibDesk's developers and provide the URL.", @"Web parser error") forKey:NSLocalizedRecoverySuggestionErrorKey]; - } - - [self didFinishStartingFindingItems:items withSuccess:[items count] > 0 error:error]; + + return items; } - (NSMutableDictionary *)dictionaryFromCitationNode:(NSXMLNode *)citationNode{ Modified: trunk/bibdesk/BDSKHubmedParser.m =================================================================== --- trunk/bibdesk/BDSKHubmedParser.m 2018-02-23 07:30:46 UTC (rev 22015) +++ trunk/bibdesk/BDSKHubmedParser.m 2018-02-23 15:44:34 UTC (rev 22016) @@ -58,7 +58,7 @@ return nil != [regex findInString:[url query]]; } -- (void)start { +- (NSArray *)itemsReturningError:(NSError **)outError { // query is 'uids=<somenumber>': // NSString *uidString = [[url query] substringWithRange:NSMakeRange(5, [[url query] length] - 5)]; @@ -65,12 +65,8 @@ NSURL *url = [self URL]; AGRegex *regex = [AGRegex regexWithPattern:@".*uids=([0-9]+).*"]; AGRegexMatch *match = [regex findInString:[url query]]; - NSError *error = nil; - if (match == nil) { - error = [NSError mutableLocalErrorWithCode:kBDSKWebParserFailed localizedDescription:NSLocalizedString(@"No search results found", @"Web parser error")]; - [error setValue:NSLocalizedString(@"Unable to parse this page. Please report this to BibDesk's developers and provide the URL.", @"Web parser error") forKey:NSLocalizedRecoverySuggestionErrorKey]; - } else { + if (match) { NSString *uidString = [match groupAtIndex:1]; NSURL *btURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/export/bibtex.cgi?uids=%@&format=.txt", [url host], uidString]]; @@ -82,34 +78,32 @@ [self addDownloadWithRequest:request contextInfo:linkedURLString]; } - [self didFinishStartingFindingItems:nil withSuccess:error == nil error:error]; + return nil; } -- (void)downloadDidFinish:(BDSKCitationDownload *)download { +- (NSArray *)itemsFromDownload:(BDSKCitationDownload *)download error:(NSError **)outError { NSString *bibTeXString = [download string]; NSError *error = [download error]; NSArray *items = nil; + NSArray *bibtexItems = nil; - if ([download failed] == NO) { + if (bibTeXString) + bibtexItems = [BDSKBibTeXParser itemsFromString:bibTeXString owner:nil error:&error]; + + if ([bibtexItems count] && [error isLocalErrorWithCode:kBDSKBibTeXParserFailed] == NO) { + BibItem *bibtexItem = [bibtexItems objectAtIndex:0]; + + // Get the fulltext URL: + [bibtexItem setField:BDSKUrlString toValue:[download contextInfo]]; - NSArray *bibtexItems = [BDSKBibTeXParser itemsFromString:bibTeXString owner:nil error:&error]; - - if ([bibtexItems count] && [error isLocalErrorWithCode:kBDSKBibTeXParserFailed] == NO) { - BibItem *bibtexItem = [bibtexItems objectAtIndex:0]; - - // Get the fulltext URL: - [bibtexItem setField:BDSKUrlString toValue:[download contextInfo]]; - - items = [NSArray arrayWithObjects:bibtexItem, nil]; - } + items = [NSArray arrayWithObjects:bibtexItem, nil]; + } else if (outError) { + *outError = error; } - [self didFinishDownload:download findingItems:items withSuccess:[items count] > 0 error:error]; + return items; } - - - + (NSDictionary *)parserInfo { NSString *parserDescription = NSLocalizedString(@"Alternative interface for queries to the PubMed database of medical literature.", @"Description for HubMed site"); return [BDSKWebParser parserInfoWithName:@"HubMed" address:@"http://www.hubmed.org/" description:parserDescription feature:BDSKParserFeaturePublic]; Modified: trunk/bibdesk/BDSKIACRParser.m =================================================================== --- trunk/bibdesk/BDSKIACRParser.m 2018-02-23 07:30:46 UTC (rev 22015) +++ trunk/bibdesk/BDSKIACRParser.m 2018-02-23 15:44:34 UTC (rev 22016) @@ -38,7 +38,6 @@ #import "BDSKIACRParser.h" #import "BibItem.h" -#import "NSError_BDSKExtensions.h" #import "NSXMLNode_BDSKExtensions.h" #import <AGRegex/AGRegex.h> @@ -62,11 +61,10 @@ } -- (void)start { +- (NSArray *)itemsReturningError:(NSError **)outError { - NSMutableArray *items = [NSMutableArray arrayWithCapacity:0]; + NSMutableArray *items = [NSMutableArray array]; - NSError *error = nil; NSURL *url = [self URL]; // is this a search results page or an individual article? @@ -76,7 +74,7 @@ NSArray *sources = nil; NSXMLElement *rootElement = [[self xmlDocument] rootElement]; if (isSearch) - sources = [rootElement nodesForXPath:@"./body//dt" error:&error]; + sources = [rootElement nodesForXPath:@"./body//dt" error:outError]; else sources = [NSArray arrayWithObjects:rootElement, nil]; @@ -129,7 +127,7 @@ } - [self didFinishStartingFindingItems:items withSuccess:YES error:nil]; + return items; } + (NSDictionary *)parserInfo { Modified: trunk/bibdesk/BDSKIEEEXploreParser.m =================================================================== --- trunk/bibdesk/BDSKIEEEXploreParser.m 2018-02-23 07:30:46 UTC (rev 22015) +++ trunk/bibdesk/BDSKIEEEXploreParser.m 2018-02-23 15:44:34 UTC (rev 22016) @@ -63,7 +63,7 @@ return [[[xmlDocument rootElement] nodesForXPath:containsAbstractPlusLinkNode error:NULL] count] > 0; } -- (BOOL)enqueueAbstractPageDownloadForURL:(NSURL *)url error:(NSError **)outError +- (void)enqueueAbstractPageDownloadForURL:(NSURL *)url error:(NSError **)outError { AGRegex *ARNumberRegex = [AGRegex regexWithPattern:@"arnumber=([0-9]+)" options:AGRegexMultiline]; AGRegexMatch *match = [ARNumberRegex findInString:[url query]]; @@ -71,7 +71,6 @@ if (match == nil) { if (outError) *outError = [NSError localErrorWithCode:kBDSKWebParserFailed localizedDescription:NSLocalizedString(@"missingARNumberKey", @"Can't get an ARNumber from the URL")]; - return NO; } else { NSString *arnumberString = [match groupAtIndex:1]; @@ -92,11 +91,10 @@ NSString *arnumberURLString = [NSString stringWithFormat:@"%@://%@/stamp/stamp.jsp?tp=&arnumber=%@", serverScheme, serverName, arnumberString]; [self addDownloadWithRequest:request contextInfo:arnumberURLString]; - return YES; } } -- (void)start { +- (NSArray *)itemsReturningError:(NSError **)outError { /* @@ -110,139 +108,113 @@ */ - NSError *error = nil; - NSMutableArray *items = [NSMutableArray arrayWithCapacity:0]; + NSError *error = nil; NSURL *url = [self URL]; - BOOL success = NO; if ([[url path] isCaseInsensitiveEqual:abstractPageURLPath] == NO && [[url path] isCaseInsensitiveEqual:searchResultPageURLPath] == NO) { // parse all links on a TOC page - NSArray *abstractPlusLinkNodes = [[[self xmlDocument] rootElement] nodesForXPath:containsAbstractPlusLinkNode error:&error]; + NSArray *abstractPlusLinkNodes = [[[self xmlDocument] rootElement] nodesForXPath:containsAbstractPlusLinkNode error:outError]; - if ([abstractPlusLinkNodes count] == 0) { - error = [NSError localErrorWithCode:kBDSKUnknownError localizedDescription:NSLocalizedString(@"Unable to find links", @"")]; - } else { - for (NSXMLNode *aplinknode in abstractPlusLinkNodes) { - NSString *hrefValue = [aplinknode stringValueOfAttribute:@"href"]; - NSURL *abstractPageURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@://%@%@", [url scheme], [url host], hrefValue]]; - - if ([self enqueueAbstractPageDownloadForURL:abstractPageURL error:&error]) - success = YES; - } + for (NSXMLNode *aplinknode in abstractPlusLinkNodes) { + NSString *hrefValue = [aplinknode stringValueOfAttribute:@"href"]; + NSURL *abstractPageURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@://%@%@", [url scheme], [url host], hrefValue]]; + + [self enqueueAbstractPageDownloadForURL:abstractPageURL error:&error]; } } else { // already on the abstract page - if ([self enqueueAbstractPageDownloadForURL:url error:&error]) - success = YES; + [self enqueueAbstractPageDownloadForURL:url error:&error]; } - [self didFinishStartingFindingItems:nil withSuccess:success error:error]; + return nil; } -- (void)downloadDidFinish:(BDSKCitationDownload *)download { +- (NSArray *)itemsFromDownload:(BDSKCitationDownload *)download error:(NSError **)outError { BibItem *newPub = nil; - NSError *error = [download error]; + NSError *error = nil; NSString *bibTeXString = nil; - if ([download failed] == NO) { - - /* - Use NSAttributedString to unescape XML entities - For example: http://ieeexplore.ieee.org/xpls/abs_all.jsp?isnumber=4977283&arnumber=4977305&count=206&index=11 - has a (tm) as an entity. + /* + Use NSAttributedString to unescape XML entities + For example: http://ieeexplore.ieee.org/xpls/abs_all.jsp?isnumber=4977283&arnumber=4977305&count=206&index=11 + has a (tm) as an entity. - http://ieeexplore.ieee.org/search/srchabstract.jsp?arnumber=259629&isnumber=6559&punumber=16&k2dockey=259629@ieeejrns&query=%28%28moll%29%3Cin%3Emetadata%29&pos=1&access=no - has smart quotes and a Greek letter (converted) and <sub> and <sup> (which are lost). - Using stringByConvertingHTMLToTeX will screw up too much stuff here, so that's not really an option. - */ - - NSAttributedString *attrString = [[[NSAttributedString alloc] initWithHTML:[download data] options:[NSDictionary dictionary] documentAttributes:NULL] autorelease]; - bibTeXString = [[attrString string] stringByCollapsingAndTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; - - /* - You'd think the IEEE would be able to produce valid BibTeX, but lots of entries have - crap like "month=jun 1--aug 1" (unquoted). They can also end a line with a double - comma (visible in the downloaded BibTeX, so not my fault). Either of these causes - btparse to choke. - - Unfortunately, BibTeX itself processes these without warnings, so there's not much - point in complaining to IEEE. BibTeX just uses the first simple value and ignores - the rest. - */ - NSScanner *scanner = [[NSScanner alloc] initWithString:bibTeXString]; - [scanner setCaseSensitive:NO]; - NSString *scanResult; - if ([scanner scanUpToString:@"month=" intoString:&scanResult]) { - [scanner scanString:@"month=" intoString:NULL]; - NSMutableString *fixed = [[scanResult mutableCopy] autorelease]; - if ([scanner scanUpToString:@"," intoString:&scanResult]) { - [fixed appendFormat:@"month={%@},", scanResult]; - [scanner scanString:@"," intoString:NULL]; - - // basically want to look for spaces and dashes between fragments; this is a heuristic, not a strict macro charset - static NSCharacterSet *badSet = nil; - if (nil == badSet) { - NSMutableCharacterSet *cset = [NSMutableCharacterSet characterSetWithRange:NSMakeRange('a', 26)]; - [cset addCharactersInRange:NSMakeRange('A', 26)]; - [cset addCharactersInString:@"0123456789"]; - badSet = [[cset invertedSet] copy]; - } - // unbraced non-letter - if ([scanResult rangeOfCharacterFromSet:badSet].length) { - [fixed appendString:[[scanner string] substringFromIndex:[scanner scanLocation]]]; - bibTeXString = fixed; - } + http://ieeexplore.ieee.org/search/srchabstract.jsp?arnumber=259629&isnumber=6559&punumber=16&k2dockey=259629@ieeejrns&query=%28%28moll%29%3Cin%3Emetadata%29&pos=1&access=no + has smart quotes and a Greek letter (converted) and <sub> and <sup> (which are lost). + Using stringByConvertingHTMLToTeX will screw up too much stuff here, so that's not really an option. + */ + + NSAttributedString *attrString = [[[NSAttributedString alloc] initWithHTML:[download data] options:[NSDictionary dictionary] documentAttributes:NULL] autorelease]; + bibTeXString = [[attrString string] stringByCollapsingAndTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + + /* + You'd think the IEEE would be able to produce valid BibTeX, but lots of entries have + crap like "month=jun 1--aug 1" (unquoted). They can also end a line with a double + comma (visible in the downloaded BibTeX, so not my fault). Either of these causes + btparse to choke. + + Unfortunately, BibTeX itself processes these without warnings, so there's not much + point in complaining to IEEE. BibTeX just uses the first simple value and ignores + the rest. + */ + NSScanner *scanner = [[NSScanner alloc] initWithString:bibTeXString]; + [scanner setCaseSensitive:NO]; + NSString *scanResult; + if ([scanner scanUpToString:@"month=" intoString:&scanResult]) { + [scanner scanString:@"month=" intoString:NULL]; + NSMutableString *fixed = [[scanResult mutableCopy] autorelease]; + if ([scanner scanUpToString:@"," intoString:&scanResult]) { + [fixed appendFormat:@"month={%@},", scanResult]; + [scanner scanString:@"," intoString:NULL]; + + // basically want to look for spaces and dashes between fragments; this is a heuristic, not a strict macro charset + static NSCharacterSet *badSet = nil; + if (nil == badSet) { + NSMutableCharacterSet *cset = [NSMutableCharacterSet characterSetWithRange:NSMakeRange('a', 26)]; + [cset addCharactersInRange:NSMakeRange('A', 26)]; + [cset addCharactersInString:@"0123456789"]; + badSet = [[cset invertedSet] copy]; } - else if ([scanner scanString:@"," intoString:NULL]) { - // empty month, unbraced, which also causes btparse to complain + // unbraced non-letter + if ([scanResult rangeOfCharacterFromSet:badSet].length) { [fixed appendString:[[scanner string] substringFromIndex:[scanner scanLocation]]]; bibTeXString = fixed; } - - // find and remove ",,\n" - NSRange doubleCommaRange = [fixed rangeOfString:@",," options:NSLiteralSearch]; - while (doubleCommaRange.length) { - NSUInteger newlineIndex = NSMaxRange(doubleCommaRange) + 1; - if (doubleCommaRange.length && newlineIndex < [fixed length] && [[NSCharacterSet newlineCharacterSet] characterIsMember:[fixed characterAtIndex:newlineIndex]]) { - [fixed replaceCharactersInRange:doubleCommaRange withString:@","]; - newlineIndex -= 1; - } - doubleCommaRange = [fixed rangeOfString:@",," options:NSLiteralSearch range:NSMakeRange(newlineIndex, [fixed length] - newlineIndex)]; + } + else if ([scanner scanString:@"," intoString:NULL]) { + // empty month, unbraced, which also causes btparse to complain + [fixed appendString:[[scanner string] substringFromIndex:[scanner scanLocation]]]; + bibTeXString = fixed; + } + + // find and remove ",,\n" + NSRange doubleCommaRange = [fixed rangeOfString:@",," options:NSLiteralSearch]; + while (doubleCommaRange.length) { + NSUInteger newlineIndex = NSMaxRange(doubleCommaRange) + 1; + if (doubleCommaRange.length && newlineIndex < [fixed length] && [[NSCharacterSet newlineCharacterSet] characterIsMember:[fixed characterAtIndex:newlineIndex]]) { + [fixed replaceCharactersInRange:doubleCommaRange withString:@","]; + newlineIndex -= 1; } + doubleCommaRange = [fixed rangeOfString:@",," options:NSLiteralSearch range:NSMakeRange(newlineIndex, [fixed length] - newlineIndex)]; } - [scanner release]; - - NSArray *newPubs = nil; - if ([NSString isEmptyString:bibTeXString] == NO) - newPubs = [BDSKBibTeXParser itemsFromString:bibTeXString owner:nil error: &error]; - else - error = [NSError mutableLocalErrorWithCode:kBDSKUnknownError localizedDescription:NSLocalizedString(@"No data returned from server", @"")]; - - newPub = [newPubs firstObject]; - - if ([NSString isEmptyString:[newPub valueOfField:BDSKUrlString inherit:NO]] && [download contextInfo]) - [newPub setField:BDSKUrlString toValue:[download contextInfo]]; - } + [scanner release]; - if (newPub == nil) { - NSString *errMsg = [[download error] localizedDescription]; - if (nil == errMsg) - errMsg = NSLocalizedString(@"Download from IEEEXplore failed.", @"error message"); - NSMutableDictionary *pubFields = [NSMutableDictionary dictionaryWithObjectsAndKeys:errMsg, BDSKTitleString, nil]; - if ([download URL]) - [pubFields setObject:[[download URL] absoluteString] forKey:BDSKUrlString]; - if ([error localizedRecoverySuggestion]) - [pubFields setObject:[error localizedRecoverySuggestion] forKey:BDSKAbstractString]; - if (bibTeXString) - [pubFields setObject:bibTeXString forKey:BDSKAnnoteString]; - newPub = [[[BibItem alloc] initWithType:BDSKMiscString citeKey:nil pubFields:pubFields isNew:YES] autorelease]; - } + NSArray *newPubs = nil; + if ([NSString isEmptyString:bibTeXString] == NO) + newPubs = [BDSKBibTeXParser itemsFromString:bibTeXString owner:nil error:&error]; + else + error = [NSError mutableLocalErrorWithCode:kBDSKUnknownError localizedDescription:NSLocalizedString(@"No data returned from server", @"")]; - [self didFinishDownload:download findingItems:[NSArray arrayWithObjects:newPub, nil] withSuccess:YES error:nil]; + newPub = [newPubs firstObject]; + + if ([NSString isEmptyString:[newPub valueOfField:BDSKUrlString inherit:NO]] && [download contextInfo]) + [newPub setField:BDSKUrlString toValue:[download contextInfo]]; + + return [NSArray arrayWithObjects:newPub, nil]; } + (NSDictionary *)parserInfo { Modified: trunk/bibdesk/BDSKInspireParser.m =================================================================== --- trunk/bibdesk/BDSKInspireParser.m 2018-02-23 07:30:46 UTC (rev 22015) +++ trunk/bibdesk/BDSKInspireParser.m 2018-02-23 15:44:34 UTC (rev 22016) @@ -74,13 +74,13 @@ return nodeCount > 0; } -- (void)start { +- (NSArray *)itemsReturningError:(NSError **)outError { if ([[[[self URL] path] lowercaseString] hasPrefix:@"/record/"]) { NSError *error = nil; NSMutableArray *items = [NSMutableArray array]; NSString *bibtexString = nil; - NSArray *preNodes = [[[self xmlDocument] rootElement] nodesForXPath:@"./body/div/div/pre[contains(text(),'@')]" error:&error]; + NSArray *preNodes = [[[self xmlDocument] rootElement] nodesForXPath:@"./body/div/div/pre[contains(text(),'@')]" error:outError]; bibtexString = [[[[preNodes firstObject] stringValue] retain] autorelease]; NSArray *bibtexItems = nil; @@ -90,10 +90,13 @@ if ([bibtexItems count] && [error isLocalErrorWithCode:kBDSKBibTeXParserFailed] == NO) { BibItem *bibtexItem = [bibtexItems objectAtIndex:0]; [items addObject:bibtexItem]; + } else if (outError) { + *outError = error; } - [self didFinishStartingFindingItems:items withSuccess:[bibtexItems count] > 0 error:error]; - return; + return items; + } else { + return [super itemsReturningError:outError]; } [super start]; Modified: trunk/bibdesk/BDSKJSTORWebParser.m =================================================================== --- trunk/bibdesk/BDSKJSTORWebParser.m 2018-02-23 07:30:46 UTC (rev 22015) +++ trunk/bibdesk/BDSKJSTORWebParser.m 2018-02-23 15:44:34 UTC (rev 22016) @@ -39,7 +39,6 @@ #import "BDSKJSTORWebParser.h" #import "BDSKBibTeXParser.h" #import "BibItem.h" -#import "NSError_BDSKExtensions.h" #import "NSXMLNode_BDSKExtensions.h" #import <AGRegex/AGRegex.h> @@ -59,11 +58,8 @@ } -- (void)start { - - NSMutableArray *items = [NSMutableArray arrayWithCapacity:1]; +- (NSArray *)itemsReturningError:(NSError **)outError { - NSError *error = nil; NSStringEncoding encoding = NSASCIIStringEncoding; // extract JSTOR article number @@ -70,10 +66,7 @@ AGRegex *jstorRegex = [AGRegex regexWithPattern:@"^/stable/([0-9]+)"]; AGRegexMatch *jstorMatch = [jstorRegex findInString:[[self URL] path]]; - if ([jstorMatch count] != 2) { - error = [NSError mutableLocalErrorWithCode:kBDSKWebParserFailed localizedDescription:NSLocalizedString(@"No search results found", @"Web parser error")]; - [error setValue:NSLocalizedString(@"Unable to parse this page. Please report this to BibDesk's developers and provide the URL.", @"Web parser error") forKey:NSLocalizedRecoverySuggestionErrorKey]; - } else { + if ([jstorMatch count] == 2) { NSString *jstorNumber = [jstorMatch groupAtIndex:1]; NSURL *url = [self URL]; @@ -86,32 +79,25 @@ [self addDownloadWithRequest:request contextInfo:nil]; } - [self didFinishStartingFindingItems:nil withSuccess:error != nil error:error]; + return nil; } -- (void)downloadDidFinish:(BDSKCitationDownload *)download { - NSError *error = [download error]; +- (NSArray *)itemsFromDownload:(BDSKCitationDownload *)download error:(NSError **)outError { NSArray *bibtexItems = nil; + NSString *bibtexString = [download string]; - if ([download failed]) { - NSString *bibtexData = [download string]; - + if (bibtexString) { // remove characters before the first @ symbol - NSRange range = [bibtexData rangeOfString:@"@"]; + NSRange range = [bibtexString rangeOfString:@"@"]; if (range.location != NSNotFound) { - bibtexData = [bibtexData substringFromIndex:range.location]; + bibtexString = [bibtexString substringFromIndex:range.location]; // parse BibTeX data - if ([BDSKBibTeXParser canParseString:bibtexData]) - bibtexItems = [BDSKBibTeXParser itemsFromString:bibtexData owner:nil error:&error]; + if ([BDSKBibTeXParser canParseString:bibtexString]) + bibtexItems = [BDSKBibTeXParser itemsFromString:bibtexString owner:nil error:outError]; } } - if ([bibtexItems count] == 0 && error == nil) { - error = [NSError mutableLocalErrorWithCode:kBDSKWebParserFailed localizedDescription:NSLocalizedString(@"No search results found", @"Web parser error")]; - [error setValue:NSLocalizedString(@"Unable to parse this page. Please report this to BibDesk's developers and provide the URL.", @"Web parser error") forKey:NSLocalizedRecoverySuggestionErrorKey]; - } - - [self didFinishDownload:download findingItems:bibtexItems withSuccess:[bibtexItems count] > 0 error:error]; + return bibtexItems; } + (NSDictionary *)parserInfo { Modified: trunk/bibdesk/BDSKLinkedBibTeXParser.m =================================================================== --- trunk/bibdesk/BDSKLinkedBibTeXParser.m 2018-02-23 07:30:46 UTC (rev 22015) +++ trunk/bibdesk/BDSKLinkedBibTeXParser.m 2018-02-23 15:44:34 UTC (rev 22016) @@ -67,19 +67,13 @@ return nodeCount > 0; } -- (void)start { +- (NSArray *)itemsReturningError:(NSError **)outError { NSString *bibtexNodePath = [[self class] linkedBibTeXNodeXPath]; NSError *error = nil; - NSArray *bibtexNodes = [[[self xmlDocument] rootElement] nodesForXPath:bibtexNodePath error:&error]; + NSArray *bibtexNodes = [[[self xmlDocument] rootElement] nodesForXPath:bibtexNodePath error:outError]; NSArray *items = nil; - // return an error when we XPath failed or we found no nodes - if ([bibtexNodes count] == 0 && error == nil) { - error = [NSError mutableLocalErrorWithCode:kBDSKWebParserFailed localizedDescription:NSLocalizedString(@"No search results found", @"Web parser error")]; - [error setValue:NSLocalizedString(@"Unable to parse this page. Please report this to BibDesk's developers and provide the URL.", @"Web parser error") forKey:NSLocalizedRecoverySuggestionErrorKey]; - } - for (NSXMLNode *bibtexNode in bibtexNodes) { NSURL *bibtexURL = nil; NSString *bibtexURLString = [[self class] linkedBibTeXURLStringFromNode:bibtexNode]; @@ -103,10 +97,10 @@ } } - [self didFinishStartingFindingItems:items withSuccess:[bibtexNodes count] != 0 error:error]; + return items; } -- (void)downloadDidFinish:(BDSKCitationDownload *)download { +- (NSArray *)itemsFromDownload:(BDSKCitationDownload *)download error:(NSError **)outError { NSMutableArray *items = [NSMutableArray array]; NSError *error = nil; NSArray *bibtexItems = nil; @@ -121,24 +115,12 @@ BibItem *bibtexItem = [bibtexItems objectAtIndex:0]; [[self class] postProcessItem:bibtexItem]; [items addObject:bibtexItem]; - } else { - // display a fake item in the table so the user knows one of the items failed to parse, but still gets the rest of the data - NSString *errMsg = [[download error] localizedDescription]; - if (errMsg == nil) - errMsg = NSLocalizedString(@"Unable to parse as BibTeX", @"Web parser error"); - NSMutableDictionary *pubFields = [NSMutableDictionary dictionaryWithObjectsAndKeys:errMsg, BDSKTitleString, nil]; - if ([download URL]) - [pubFields setObject:[[download URL] absoluteString] forKey:BDSKUrlString]; - if ([error localizedRecoverySuggestion]) - [pubFields setObject:[error localizedRecoverySuggestion] forKey:BDSKAbstractString]; - if (bibtexString) - [pubFields setObject:bibtexString forKey:BDSKAnnoteString]; - BibItem *errorItem = [[BibItem alloc] initWithType:BDSKMiscString citeKey:nil pubFields:pubFields isNew:YES]; - [items addObject:errorItem]; - [errorItem release]; } - [self didFinishDownload:download findingItems:items withSuccess:YES error:nil]; + if ([items count] == 0 && outError) + *outError = error; + + return items; } + (NSDictionary *)parserInfo { Modified: trunk/bibdesk/BDSKMASParser.m =================================================================== --- trunk/bibdesk/BDSKMASParser.m 2018-02-23 07:30:46 UTC (rev 22015) +++ trunk/bibdesk/BDSKMASParser.m 2018-02-23 15:44:34 UTC (rev 22016) @@ -41,7 +41,6 @@ #import "BibItem.h" #import "NSString_BDSKExtensions.h" #import "NSXMLNode_BDSKExtensions.h" -#import "NSError_BDSKExtensions.h" #import <AGRegex/AGRegex.h> @@ -63,23 +62,17 @@ return [nodes count] > 0; } -- (void)start { +- (NSArray *)itemsReturningError:(NSError **)outError { - NSError *error = nil; - - NSArray *nodes = [xmlDocument nodesForXPath:@"./body//a[starts-with(@href,'../../UserInput/EditPublication?id=')]" error:&error]; + NSArray *nodes = [xmlDocument nodesForXPath:@"./body//a[starts-with(@href,'../../UserInput/EditPublication?id=')]" error:outError]; NSString *pattern = @"^\\.\\./\\.\\./UserInput/EditPublication\\?id\\=([0-9]*)$"; if ([nodes count] == 0) { - nodes = [xmlDocument nodesForXPath:@"./body//a[starts-with(@href,'/Publication/')]" error:&error]; + nodes = [xmlDocument nodesForXPath:@"./body//a[starts-with(@href,'/Publication/')]" error:outError]; pattern = @"^Publication/([0-9]*)/"; if ([nodes count] == 0) { - nodes = [xmlDocument nodesForXPath:@"./body//a[starts-with(@href,'/Publication/')]" error:&error]; + nodes = [xmlDocument nodesForXPath:@"./body//a[starts-with(@href,'/Publication/')]" error:outError]; pattern = @"^/Publication/([0-9]*)/"; - if ([nodes count] == 0 && error == nil) { - error = [NSError mutableLocalErrorWithCode:kBDSKWebParserFailed localizedDescription:NSLocalizedString(@"No search results found", @"Web parser error")]; - [error setValue:NSLocalizedString(@"Unable to parse this page. Please report this to BibDesk's developers and provide the URL.", @"Web parser error") forKey:NSLocalizedRecoverySuggestionErrorKey]; - } } } @@ -103,30 +96,19 @@ [self addDownloadWithRequest:request contextInfo:nil]; } - [self didFinishStartingFindingItems:nil withSuccess:error == nil error:error]; + return nil; } -- (void)downloadDidFinish:(BDSKCitationDownload *)download { - NSError *error = [download error]; +- (NSArray *)itemsFromDownload:(BDSKCitationDownload *)download error:(NSError **)outError { + NSError *error = nil; NSString *bibtexString = [download string]; NSArray *bibtexItems = nil; NSArray *items = nil; if (bibtexString) - items = [BDSKBibTeXParser itemsFromString:[bibtexString stringWithPhoneyCiteKeys:[BibItem defaultCiteKey]] owner:nil error:&error]; + items = [BDSKBibTeXParser itemsFromString:[bibtexString stringWithPhoneyCiteKeys:[BibItem defaultCiteKey]] owner:nil error:outError]; - if ([items count] == 0) { - // display a fake item in the table so the user knows one of the items failed to parse, but still gets the rest of the data - NSString *errMsg = [[download error] localizedDescription]; - if (errMsg == nil) - errMsg = NSLocalizedString(@"Unable to parse as BibTeX", @"Web parser error"); - NSDictionary *pubFields = [NSDictionary dictionaryWithObjectsAndKeys:errMsg, BDSKTitleString, [[download URL] absoluteString], BDSKUrlString, nil]; - BibItem *errorItem = [[BibItem alloc] initWithType:BDSKMiscString citeKey:nil pubFields:pubFields isNew:YES]; - items = [NSArray arrayWithObjects:errorItem, nil]; - [errorItem release]; - } - - [self didFinishDownload:download findingItems:items withSuccess:YES error:nil]; + return items; } + (NSDictionary *)parserInfo { Modified: trunk/bibdesk/BDSKMathSciNetParser.m =================================================================== --- trunk/bibdesk/BDSKMathSciNetParser.m 2018-02-23 07:30:46 UTC (rev 22015) +++ trunk/bibdesk/BDSKMathSciNetParser.m 2018-02-23 15:44:34 UTC (rev 22016) @@ -39,7 +39,6 @@ #import "BDSKMathSciNetParser.h" #import "BDSKBibTeXParser.h" #import "BibItem.h" -#import "NSError_BDSKExtensions.h" #import <AGRegex/AGRegex.h> #define MSNBATCHSIZE 50u @@ -62,20 +61,14 @@ // Finds strings of type MR1234567 in the current page. // Creates a list of their IDs (without leading zeroes), and retrieves the BibItems for them. // Returns an array with those BibItems. -- (void)start { +- (NSArray *)itemsReturningError:(NSError **)outError { - NSError *error = nil; - AGRegex * MRRegexp = [AGRegex regexWithPattern:@"MR0*([0-9]+)" options:AGRegexMultiline]; NSArray * regexpResults = [MRRegexp findAllInString:[[self xmlDocument] XMLString]]; NSArray * requests = nil; - if (0 == [regexpResults count]) {// no matches, return an error - error = [NSError mutableLocalErrorWithCode:kBDSKWebParserFailed localizedDescription:NSLocalizedString(@"No search results found", @"Web parser error")]; - [error setValue:NSLocalizedString(@"Unable to parse this page. Please report this to BibDesk's developers and provide the URL.", @"Web parser error") forKey:NSLocalizedRecoverySuggestionErrorKey]; - } - else { + if ([regexpResults count]) { NSMutableArray * IDArray = [NSMutableArray arrayWithCapacity:[regexpResults count]]; for (AGRegexMatch * match in regexpResults) { @@ -85,42 +78,25 @@ } } - requests = [BDSKMathSciNetParser bibTeXRequestsForMRIDs:IDArray referrer:[self URL] error:&error]; + requests = [BDSKMathSciNetParser bibTeXRequestsForMRIDs:IDArray referrer:[self URL] error:outError]; for (NSURLRequest *request in requests) [self addDownloadWithRequest:request contextInfo:nil]; } - [self didFinishStartingFindingItems:nil withSuccess:[requests count] > 0 error:error]; + + return nil; } -- (void)downloadDidFinish:(BDSKCitationDownload *)download { +- (NSArray *)itemsFromDownload:(BDSKCitationDownload *)download error:(NSError **)outError { NSArray *results = nil; - NSError *error = [download error]; NSArray *bibtexItems = nil; NSString *bibTeXString = [download string]; if (bibTeXString) - results = [BDSKMathSciNetParser bibItemsFromBibTeXString:bibTeXString fromURL:[download URL] error:&error]; + results = [BDSKMathSciNetParser bibItemsFromBibTeXString:bibTeXString fromURL:[download URL] error:outError]; - if ([results count] == 0) { - // display a fake item in the table so the user knows one of the items failed to parse, but still gets the rest of the data - NSString *errMsg = [[download error] localizedDescription]; - if (errMsg == nil) - errMsg = NSLocalizedString(@"Unable to parse as BibTeX", @"Web parser error"); - NSMutableDictionary *pubFields = [NSMutableDictionary dictionaryWithObjectsAndKeys:errMsg, BDSKTitleString, nil]; - if ([download URL]) - [pubFields setObject:[[download URL] absoluteString] forKey:BDSKUrlString]; - if ([error localizedRecoverySuggestion]) - [pubFields setObject:[error localizedRecoverySuggestion] forKey:BDSKAbstractString]; - if (bibTeXString) - [pubFields setObject:bibTeXString forKey:BDSKAnnoteString]; - BibItem *errorItem = [[BibItem alloc] initWithType:BDSKMiscString citeKey:nil pubFields:pubFields isNew:YES]; - results = [NSArray arrayWithObjects:errorItem, nil]; - [errorItem release]; - } - - [self didFinishDownload:download findingItems:results withSuccess:YES error:nil]; + return results; } // Turns an array of MR ID numbers into an array of NSURLRequest objects to download the bibTeX citations. Modified: trunk/bibdesk/BDSKNumdamParser.m =================================================================== --- trunk/bibdesk/BDSKNumdamParser.m 2018-02-23 07:30:46 UTC (rev 22015) +++ trunk/bibdesk/BDSKNumdamParser.m 2018-02-23 15:44:34 UTC (rev 22016) @@ -39,9 +39,7 @@ #import "BDSKNumdamParser.h" #import "BDSKMathSciNetParser.h" #import "BDSKZentralblattParser.h" -#import "NSError_BDSKExtensions.h" #import "BibItem.h" -#import "BDSKComplexString.h" #import <AGRegex/AGRegex.h> @@ -61,11 +59,9 @@ // Find references from Zentralblatt Math referred to by the page. Then look them up. Insert link to NUMDAM in the item's own record. // (Support for MatSciNet is currently commented out as their lookup script requires online-style MR1234567 identifiers and NUMDAM uses paper-style identifiers a la 16,957b.) -- (void)start { - - NSError * error = nil; +- (NSArray *)itemsReturningError:(NSError **)outError { - NSArray * tableCells = [[[self xmlDocument] rootElement] nodesForXPath:@".//td[@id='contenu']" error:&error]; + NSArray * tableCells = [[[self xmlDocument] rootElement] nodesForXPath:@".//td[@id='contenu']" error:outError]; NSXMLElement * tableCell = [tableCells objectAtIndex:0]; NSString * content = [tableCell stringValue]; @@ -121,7 +117,7 @@ } /* - NSArray * MRRequests = [BDSKMathSciNetParser bibTeXRequestsForZMathIDs:ZMathReferences referrer:[self URL] error:&error]; + NSArray * MRRequests = [BDSKMathSciNetParser bibTeXRequestsForZMathIDs:ZMathReferences referrer:[self URL] error:outError]; for (NSURLRequest *request in MRRequests) { NSDictionary *contextInfo = [NSDictionary dictionaryWithObjectsAndKeys:[BDSKMathSciNetParser class], @"parserClass", firstMRIDIsOwnId ? content : nil, @"content", nil]; @@ -130,7 +126,7 @@ } */ - NSArray * ZMathRequests = [BDSKZentralblattParser bibTeXRequestsForZMathIDs:ZMathReferences referrer:[self URL] error:&error]; + NSArray * ZMathRequests = [BDSKZentralblattParser bibTeXRequestsForZMathIDs:ZMathReferences referrer:[self URL] error:outError]; for (NSURLRequest *request in ZMathRequests) { NSDictionary *contextInfo = [NSDictionary dictionaryWithObjectsAndKeys:[BDSKZentralblattParser class], @"parserClass", firstZMathIDIsOwnId ? content : nil, @"content", nil]; @@ -138,13 +134,11 @@ firstZMathIDIsOwnId = NO; } - BOOL success = /* [MRRequests count] > 0 && */ [ZMathRequests count] > 0; - [self didFinishStartingFindingItems:nil withSuccess:success error:error]; + return nil; } -- (void)downloadDidFinish:(BDSKCitationDownload *)download { +- (NSArray *)itemsFromDownload:(BDSKCitationDownload *)download error:(NSError **)outError { NSArray *results = nil; - NSError *error = [download error]; NSArray *bibtexItems = nil; NSString *bibTeXString = [download string]; NSDictionary *contextInfo = [download contextInfo]; @@ -152,24 +146,9 @@ NSString *content = [contextInfo objectForKey:@"content"]; if (bibTeXString) - results = [parserClass bibItemsFromBibTeXString:bibTeXString fromURL:[download URL] error:&error]; + results = [parserClass bibItemsFromBibTeXString:bibTeXString fromURL:[download URL] error:outError]; - if ([results count] == 0) { - // display a fake item in the table so the user knows one of the items failed to parse, but still gets the rest of the data - NSString *errMsg = [[download error] localizedDescription]; - if (errMsg == nil) - errMsg = NSLocalizedString(@"Unable to parse as BibTeX", @"Web parser error"); - NSMutableDictionary *pubFields = [NSMutableDictionary dictionaryWithObjectsAndKeys:errMsg, BDSKTitleString, nil]; - if ([download URL]) - [pubFields setObject:[[download URL] absoluteString] forKey:BDSKUrlString]; - if ([error localizedRecoverySuggestion]) - [pubFields setObject:[error localizedRecoverySuggestion] forKey:BDSKAbstractString]; - if (bibTeXString) - [pubFields setObject:bibTeXString forKey:BDSKAnnoteString]; - BibItem *errorItem = [[BibItem alloc] initWithType:BDSKMiscString citeKey:nil pubFields:pubFields isNew:YES]; - results = [NSArray arrayWithObjects:errorItem, nil]; - [errorItem release]; - } else if (content) { + if ([results count] > 0 && content != nil) { // add Numdam URL to item's own record BibItem *item = [results objectAtIndex:0]; if ( [item isKindOfClass:[BibItem class]] ) { @@ -189,7 +168,7 @@ } } - [self didFinishDownload:download findingItems:results withSuccess:YES error:nil]; + return results; } + (NSDictionary *)parserInfo { Modified: trunk/bibdesk/BDSKProjectEuclidParser.m =================================================================== --- trunk/bibdesk/BDSKProjectEuclidParser.m 2018-02-23 07:30:46 UTC (rev 22015) +++ trunk/bibdesk/BDSKProjectEuclidParser.m 2018-02-23 15:44:34 UTC (rev 22016) @@ -39,9 +39,7 @@ #import "BDSKProjectEuclidParser.h" #import "BDSKMathSciNetParser.h" #import "BDSKZentralblattParser.h" -#import "NSError_BDSKExtensions.h" #import "BibItem.h" -#import "BDSKComplexString.h" #import <AGRegex/AGRegex.h> @@ -60,24 +58,15 @@ } // Find references for Mathematical Reviews and Zentralblatt Math in the page. Then look them up, giving preference to MSN if both are available. -- (void)start { +- (NSArray *)itemsReturningError:(NSError **)outError { - NSError * error; - - NSArray * identifiers = [[[self xmlDocument] rootElement] nodesForXPath:@".//div[@id='identifier']/p" error:&error]; + NSArray * identifiers = [[[self xmlDocument] rootElement] nodesForXPath:@".//div[@id='identifier']/p" error:outError]; NSArray *MRRequests = nil; NSArray *ZMathRequests = nil; - if ( [identifiers count] == 0 ) {// no matches, return an error + if ( [identifiers count] ) { - if (error == nil) { - error = [NSError mutableLocalErrorWithCode:kBDSKWebParserFailed localizedDescription:NSLocalizedString(@"No search results found", @"Web parser error")]; - [error setValue:NSLocalizedString(@"Unable to parse this page. Please report this to BibDesk's developers and provide the URL.", @"Web parser error") forKey:NSLocalizedRecoverySuggestionErrorKey]; - } - - } else { - NSXMLElement * identifier = [identifiers objectAtIndex:0]; NSString * identifierString = [identifier stringValue]; @@ -97,7 +86,7 @@ } // Set up arrays for the lists of MathSciNet and Zentralblatt IDs. These will have the ID for the current element at position 0 and contain NSNull when no ID is found for the respective service. - NSArray * references = [[[self xmlDocument] rootElement] nodesForXPath:@".//div[@id='references']/div[@class='ref-block']" error:&error]; + NSArray * references = [[[self xmlDocument] rootElement] nodesForXPath:@".//div[@id='references']/div[@class='ref-block']" error:outError]; NSMutableArray * MRIDs = [NSMutableArray arrayWithObjects:myMRID, nil]; NSMutableArray * ZMathIDs = [NSMutableArray arrayWithObjects:myZMathID, nil]; @@ -116,7 +105,7 @@ } } - MRRequests = [BDSKMathSciNetParser bibTeXRequestsForMRIDs:MRIDs referrer:[self URL] error:&error]; + MRRequests = [BDSKMathSciNetParser bibTeXRequestsForMRIDs:MRIDs referrer:[self URL] error:outError]; NSString *myIdentifier = myMRID ? identifierString : nil; for (NSURLRequest *request in MRRequests) { @@ -125,7 +114,7 @@ myIdentifier = nil; } - ZMathRequests = [BDSKZentralblattParser bibTeXRequestsForZMathIDs:ZMathIDs referrer:[self URL] error:&error]; + ZMathRequests = [BDSKZentralblattParser bibTeXRequestsForZMathIDs:ZMathIDs referrer:[self URL] error:outError]; myIdentifier = myZMathID ? identifierString : nil; for (NSURLRequest *request in ZMathRequests) { @@ -135,13 +124,13 @@ } } - BOOL success = [MRRequests count] > 0 || [ZMathRequests count] > 0; - [self didFinishStartingFindingItems:nil withSuccess:success error:error]; + + return nil; } -- (void)downloadDidFinish:(BDSKCitationDownload *)download { +- (NSArray *)itemsFromDownload:(BDSKCitationDownload *)download error:(NSError **)outError { NSArray *results = nil; - NSError *error = [download error]; + NSError *error = nil; NSArray *bibtexItems = nil; NSString *bibTeXString = [download string]; NSDictionary *contextInfo = [download contextInfo]; @@ -152,22 +141,7 @@ // parse the bibTeX string with the correct parser results = [parserClass bibItemsFromBibTeXString:bibTeXString fromURL:[download URL] error:&error]; - if ([results count] == 0) { - // display a fake item in the table so the user knows one of the items failed to parse, but still gets the rest of the data - NSString *errMsg = [[download error] localizedDescription]; - if (errMsg == nil) - errMsg = NSLocalizedString(@"Unable to parse as BibTeX", @"Web parser error"); - NSMutableDictionary *pubFields = [NSMutableDictionary dictionaryWithObjectsAndKeys:errMsg, BDSKTitleString, nil]; - if ([download URL]) - [pubFields setObject:[[download URL] absoluteString] forKey:BDSKUrlString]; - if ([error localizedRecoverySuggestion]) - [pubFields setObject:[error localizedRecoverySuggestion] forKey:BDSKAbstractString]; - if (bibTeXString) - [pubFields setObject:bibTeXString forKey:BDSKAnnoteString]; - BibItem *errorItem = [[BibItem alloc] initWithType:BDSKMiscString citeKey:nil pubFields:pubFields isNew:YES]; - results = [NSArray arrayWithObjects:errorItem, nil]; - [errorItem release]; - } else if (myIdentifier) { + if ([results count] > 0 && myIdentifier != nil) { // add Project Euclid URL to item's own record NSObject * item = [results objectAtIndex:0]; if ( [item isKindOfClass:[BibItem class]] ) { @@ -186,7 +160,7 @@ } } - [self didFinishDownload:download findingItems:results withSuccess:YES error:nil]; + return results; } Modified: trunk/bibdesk/BDSKWebParser.h =================================================================== --- trunk/bibdesk/BDSKWebParser.h 2018-02-23 07:30:46 UTC (rev 22015) +++ trunk/bibdesk/BDSKWebParser.h 2018-02-23 15:44:34 UTC (rev 22016) @@ -55,6 +55,7 @@ NSXMLDocument *xmlDocument; NSURL *URL; id<BDSKWebParserDelegate> delegate; + BOOL finishedStarting; } // this method is the main entry point for the BDSKWebParser class @@ -74,11 +75,13 @@ @property (nonatomic, readonly) DOMDocument *domDocument; @property (nonatomic, readonly) NSXMLDocument *xmlDocument; @property (nonatomic, readonly) NSURL *URL; + @property (nonatomic, assign) id<BDSKWebParserDelegate> delegate; -// these two methods should be implemented by subclasses -+ (BOOL)canParseDocument:(DOMDocument *)domDocument xmlDocument:(NSXMLDocument *)xmlDocument fromURL:(NSURL *)url; -+ (NSDictionary *)parserInfo; +// set at the end of -start, to know thereis not more coming, so we may finish +@property (nonatomic) BOOL finishedStarting; +// whether the parser can finish, e.g. no pending additions or downloads +@property (nonatomic, readonly) BOOL canFinish; - (id)initWithDocument:(DOMDocument *)aDomDocument xmlDocument:(NSXMLDocument *)aXmlDocument fromURL:(NSURL *)aURL; @@ -85,10 +88,15 @@ - (void)start; - (void)cancel; -// convenience method to call the various delegate methods if needed -// subclasses can use this at the end of sartWithDelegate: instead of calling the delegate methods -- (void)didFinishStartingFindingItems:(NSArray *)items withSuccess:(BOOL)success error:(NSError *)error; +// whether the parsershould finish with success, can be overridden by subclasses returning items async +- (BOOL)succeededWithItems:(NSArray *)items; +// the next three methods should be implemented by subclasses ++ (BOOL)canParseDocument:(DOMDocument *)domDocument xmlDocument:(NSXMLDocument *)xmlDocument fromURL:(NSURL *)url; ++ (NSDictionary *)parserInfo; + +- (NSArray *)itemsReturningError:(NSError **)outError; + @end @protocol BDSKWebParserDelegate <NSObject> Modified: trunk/bibdesk/BDSKWebParser.m =================================================================== --- trunk/bibdesk/BDSKWebParser.m 2018-02-23 07:30:46 UTC (rev 22015) +++ trunk/bibdesk/BDSKWebParser.m 2018-02-23 15:44:34 UTC (rev 22016) @@ -57,6 +57,7 @@ #import "BDSKCOinSParser.h" #import "BDSKIEEEXploreParser.h" #import "BDSKMASParser.h" +#import "BibItem.h" #import "NSError_BDSKExtensions.h" #import "BDSKRuntime.h" @@ -67,7 +68,8 @@ @implementation BDSKWebParser -@synthesize domDocument, xmlDocument, URL, delegate; +@synthesize domDocument, xmlDocument, URL, delegate, finishedStarting; +@dynamic canFinish; + (NSArray *)webParserClasses { static NSArray *webParsers = nil; @@ -206,18 +208,41 @@ [super dealloc]; } -- (void)start {} +- (void)start { + NSError *error = nil; + + NSArray *items = [self itemsReturningError:&error]; + + BOOL success = [self succeededWithItems:items]; + + if (success == NO && error == nil) { + error = [NSError mutableLocalErrorWithCode:kBDSKWebParserFailed localizedDescription:NSLocalizedString(@"No search results found", @"Web parser error")]; + [error setValue:NSLocalizedString(@"Unable to parse this page. Please report this to BibDesk's developers and provide the URL.", @"Web parser error") forKey:NSLocalizedRecoverySuggestionErrorKey]; + } + + if ([items count] > 0) + [[self delegate] webParser:self didFindItems:items]; + + [self setFinishedStarting:YES]; + + if ([self canFinish]) + [[self delegate] webParser:self didFinishWithSuccess:success error:error]; +} - (void)cancel { [self setDelegate:nil]; } -- (void)didFinishStartingFindingItems:(NSArray *)items withSuccess:(BOOL)success error:(NSError *)error { - if ([items count] > 0) - [[self delegate] webParser:self didFindItems:items]; - [[self delegate] webParser:self didFinishWithSuccess:success error:error]; +- (BOOL)canFinish { + return [self finishedStarting]; } +- (BOOL)succeededWithItems:(NSArray *)items { + return [items count] > 0; +} + +- (NSArray *)itemsReturningError:(NSError **)outError { return nil; } + + (BOOL)canParseDocument:(DOMDocument *)domDocument xmlDocument:(NSXMLDocument *)xmlDocument fromURL:(NSURL *)url { return NO; } + (NSDictionary *)parserInfo { return nil; } Modified: trunk/bibdesk/BDSKZentralblattParser.m =================================================================== --- trunk/bibdesk/BDSKZentralblattParser.m 2018-02-23 07:30:46 UTC (rev 22015) +++ trunk/bibdesk/BDSKZentralblattParser.m 2018-02-23 15:44:34 UTC (rev 22016) @@ -39,7 +39,6 @@ #import "BDSKZentralblattParser.h" #import "BDSKBibTeXParser.h" #import "BibItem.h" -#import "NSError_BDSKExtensions.h" #import <AGRegex/AGRegex.h> #define ZMATHBATCHSIZE 100u @@ -62,7 +61,7 @@ // Find occurrences of strings Zbl [pre]1234.56789 or JFM 12.3456.78 on the page. // Extract their IDs and look them up. // Return the resulting BibItems. -- (void)start { +- (NSArray *)itemsReturningError:(NSError **)outError { NSError *error = nil; @@ -71,11 +70,7 @@ NSArray * requests = nil; - if (0 == [regexpResults count]) {// no matches, return an error - error = [NSError mutableLocalErrorWithCode:kBDSKWebParserFailed localizedDescription:NSLocalizedString(@"No search results found", @"Web parser error")]; - [error setValue:NSLocalizedString(@"Unable to parse this page. Please report this to BibDesk's developers and provide the URL.", @"Web parser error") forKey:NSLocalizedRecoverySuggestionErrorKey]; - } - else { + if ([regexpResults count]) { NSMutableArray * IDArray = [NSMutableArray arrayWithCapacity:[regexpResults count]]; for (AGRegexMatch *match in regexpResults) { @@ -85,42 +80,23 @@ } } - requests = [BDSKZentralblattParser bibTeXRequestsForZMathIDs:IDArray referrer:[self URL] error:&error]; + requests = [BDSKZentralblattParser bibTeXRequestsForZMathIDs:IDArray referrer:[self URL] error:outError]; for (NSURLRequest *request in requests) [self addDownloadWithRequest:request contextInfo:nil]; } - [self didFinishStartingFindingItems:nil withSuccess:[requests count] > 0 error:error]; + return nil; } -- (void)downloadDidFinish:(BDSKCitationDownload *)download { +- (NSArray *)itemsFromDownload:(BDSKCitationDownload *)download error:(NSError **)outError { NSArray *results = nil; - NSError *error = nil; - NSArray *bibtexItems = nil; NSString *bibTeXString = [download string]; if (bibTeXString) - results = [BDSKZentralblattParser bibItemsFromBibTeXString:bibTeXString fromURL:[download URL] error:&error]; + results = [BDSKZentralblattParser bibItemsFromBibTeXString:bibTeXString fromURL:[download URL] error:outError]; - if ([results count] == 0) { - // display a fake item in the table so the user knows one of the items failed to parse, but still gets the rest of the data - NSString *errMsg = [[download error] localizedDescription]; - if (errMsg == nil) - errMsg = NSLocalizedString(@"Unable to parse as BibTeX", @"Web parser error"); - NSMutableDictionary *pubFields = [NSMutableDictionary dictionaryWithObjectsAndKeys:errMsg, BDSKTitleString, nil]; - if ([download URL]) - [pubFields setObject:[[download URL] absoluteString] forKey:BDSKUrlString]; - if ([error localizedRecoverySuggestion]) - [pubFields setObject:[error localizedRecoverySuggestion] forKey:BDSKAbstractString]; - if (bibTeXString) - [pubFields setObject:bibTeXString forKey:BDSKAnnoteString]; - BibItem *errorItem = [[BibItem alloc] initWithType:BDSKMiscString citeKey:nil pubFields:pubFields isNew:YES]; - results = [NSArray arrayWithObjects:errorItem, nil]; - [errorItem release]; - } - -[self didFinishDownload:download findingItems:results withSuccess:YES error:nil]; + return results; } // Turns an array of Zentralblatt Math IDs into an array of NSURLRequest objects for bibtex data. Modified: trunk/bibdesk/English.lproj/Localizable.strings =================================================================== (Binary files differ) Modified: trunk/bibdesk/French.lproj/Localizable.strings =================================================================== (Binary files differ) Modified: trunk/bibdesk/German.lproj/Localizable.strings =================================================================== (Binary files differ) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ Bibdesk-commit mailing list Bibdesk-commit@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bibdesk-commit