我现在已经隔离了Redland RDF库的一个问题,我之前也问过这个问题。所以我仍然在想:是什么导致下面的测试用例失败?
实际上应该发生的事情如下:我正在构建两个RDF模型,每个模型都包含一个事件ID。我使用这些事件id作为字典(哈希表)的键。由于RDF模型是C结构体,我将它们包装在Objective C类中,以获得可以存储在字典中的内容。现在,当我尝试通过这些不同的键从字典中检索两个RDF模型时,我总是得到相同的 RDF模型。RDF模型的指针值是不同的,但是所有包含的RDF节点显然是相同的。我错过了什么?(顺便说一句,我很确定这个问题不是所有混淆的工件:)
//
// RedlandRdfStandaloneTests.h
//
#import <SenTestingKit/SenTestingKit.h>
@interface RedlandRdfStandaloneTests : SenTestCase
@end
//
// RedlandRdfStandaloneTests.m
//
#import "librdf.h"
#import "RdfModelWrapper.h"
#import "RedlandRdfStandaloneTests.h"
// namespace URIs
#define OBFUSCATED6_NAMESPACE @"http://www.OBFUSCATED1.com/2013/05/OBFUSCATED7#"
// datatype properties
#define OBFUSCATED6_EVENT_ID_LOCAL_NAME @"eventId"
// individuals
#define OBFUSCATED6_CALENDAR_EVENT_LOCAL_NAME @"CalendarEvent"
#define IDENTIFIER_1 @"dc4bc97ugu7kl5hoh2spmanob4"
#define IDENTIFIER_2 @"cbd3mghbgas8juuh4l88rt04ec"
@interface RedlandRdfStandaloneTests ()
@property (assign, readonly) librdf_world *rdfWorld;
@property (assign, readonly) librdf_storage *rdfStorage;
@property (assign, readonly) librdf_node *rdfTypeProperty;
@property (assign, readonly) librdf_uri *obfuscated8NamespaceUri;
@property (assign, readonly) librdf_node *obfuscated8EventIdProperty;
@property (assign, readonly) librdf_node *obfuscated8CalendarEventIndividual;
@property (assign, readonly) librdf_parser *rdfParser;
@property (assign, readonly) librdf_uri *baseUri;
@property (strong, readonly) NSString *rdfModel1AsString;
@property (strong, readonly) NSString *rdfModel2AsString;
@end
@implementation RedlandRdfStandaloneTests
- (void)test
{
NSMutableDictionary *identifiersToRdfModelWrappers = [NSMutableDictionary dictionary];
librdf_model *rdfModel;
{
rdfModel = librdf_new_model(_rdfWorld, _rdfStorage, NULL);
librdf_parser_parse_string_into_model(_rdfParser, (const unsigned char *)_rdfModel1AsString.UTF8String, _baseUri, rdfModel);
RdfModelWrapper *rdfModelWrapper = [[RdfModelWrapper alloc] initWithRdfModel:rdfModel];
[identifiersToRdfModelWrappers setObject:rdfModelWrapper forKey:IDENTIFIER_1];
[self writeModel:rdfModel withRdfWorld:_rdfWorld]; // #1: ok -- same as _rdfModel1AsString with eventId same as IDENTIFIER_1
}
{
rdfModel = librdf_new_model(_rdfWorld, _rdfStorage, NULL);
librdf_parser_parse_string_into_model(_rdfParser, (const unsigned char *)_rdfModel2AsString.UTF8String, _baseUri, rdfModel);
RdfModelWrapper *rdfModelWrapper = [[RdfModelWrapper alloc] initWithRdfModel:rdfModel];
[identifiersToRdfModelWrappers setObject:rdfModelWrapper forKey:IDENTIFIER_2];
[self writeModel:rdfModel withRdfWorld:_rdfWorld]; // #2: ok -- same as _rdfModel2AsString with eventId same as IDENTIFIER_2
}
{
RdfModelWrapper *rdfModelWrapper = [identifiersToRdfModelWrappers objectForKey:IDENTIFIER_1];
rdfModel = rdfModelWrapper.rdfModel;
librdf_node *eventResource = librdf_model_get_source(rdfModel, _rdfTypeProperty, _obfuscated8CalendarEventIndividual);
librdf_node *eventIdLiteral = librdf_model_get_target(rdfModel, eventResource, _obfuscated8EventIdProperty);
NSString *eventId = [NSString stringWithCString:librdf_node_get_literal_value_as_latin1(eventIdLiteral) encoding:NSISOLatin1StringEncoding];
[self writeModel:rdfModel withRdfWorld:_rdfWorld]; // #3: error -- same as _rdfModel2AsString with eventId same as IDENTIFIER_2
STAssertEqualObjects(IDENTIFIER_1, eventId, nil); // #4: fails
}
{
RdfModelWrapper *rdfModelWrapper = [identifiersToRdfModelWrappers objectForKey:IDENTIFIER_2];
rdfModel = rdfModelWrapper.rdfModel;
librdf_node *eventResource = librdf_model_get_source(rdfModel, _rdfTypeProperty, _obfuscated8CalendarEventIndividual);
librdf_node *eventIdLiteral = librdf_model_get_target(rdfModel, eventResource, _obfuscated8EventIdProperty);
NSString *eventId = [NSString stringWithCString:librdf_node_get_literal_value_as_latin1(eventIdLiteral) encoding:NSISOLatin1StringEncoding];
[self writeModel:rdfModel withRdfWorld:_rdfWorld]; // #5: ok -- same as _rdfModel2AsString with eventId same as IDENTIFIER_2
STAssertEqualObjects(IDENTIFIER_2, eventId, nil); // #6: ok
}
}
- (void)writeModel:(librdf_model *)rdfModel withRdfWorld:(librdf_world *)rdfWorld
{
raptor_world *raptorWorld = librdf_world_get_raptor(rdfWorld);
raptor_iostream *stream = raptor_new_iostream_to_file_handle(raptorWorld, stdout);
NSAssert(stream != nil, @"cannot create stream");
int flag = librdf_model_write(rdfModel, stream);
NSAssert(flag == 0, @"librdf_model_write() failed: %d", flag);
raptor_free_iostream(stream);
}
#pragma mark -
#pragma mark override SenTestCase
- (void)setUp
{
_rdfWorld = librdf_new_world();
librdf_world_open(_rdfWorld);
_rdfStorage = librdf_new_storage(_rdfWorld, "memory", NULL, NULL);
_rdfTypeProperty = LIBRDF_MS_type(_rdfWorld);
_obfuscated8NamespaceUri = librdf_new_uri(_rdfWorld, (const unsigned char *)OBFUSCATED6_NAMESPACE.UTF8String);
_obfuscated8EventIdProperty = librdf_new_node_from_uri_local_name(_rdfWorld, _obfuscated8NamespaceUri, (const unsigned char *)OBFUSCATED6_EVENT_ID_LOCAL_NAME.UTF8String);
_obfuscated8CalendarEventIndividual = librdf_new_node_from_uri_local_name(_rdfWorld, _obfuscated8NamespaceUri, (const unsigned char *)OBFUSCATED6_CALENDAR_EVENT_LOCAL_NAME.UTF8String);
_rdfParser = librdf_new_parser(_rdfWorld, NULL, "application/rdf+xml", NULL);
NSAssert(_rdfParser != nil, @"no RDF parser");
_baseUri = librdf_new_uri(_rdfWorld, (const unsigned char *)"http://www.w3.org/1999/02/22-rdf-syntax-ns#");
_rdfModel1AsString = @"<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:j.0="http://www.OBFUSCATED1.com/2013/05/OBFUSCATED7#"
xmlns:owl="http://www.w3.org/2002/07/owl#"
xmlns="http://www.OBFUSCATED1.com/2013/05/OBFUSCATED2#"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:mo="http://purl.org/ontology/mo/">
<rdf:Description rdf:about="http://www.OBFUSCATED5.com/event/show/2224183">
<rdf:type rdf:resource="http://www.w3.org/2000/01/rdf-schema#Resource"/>
<rdf:type rdf:resource="http://www.OBFUSCATED1.com/2013/05/OBFUSCATED7#CalendarEvent"/>
<j.0:eventId>dc4bc97ugu7kl5hoh2spmanob4</j.0:eventId>
<j.0:hasOrganization rdf:resource="http://www.OBFUSCATED1.com/2013/05/MDW#MDW"/>
</rdf:Description>
</rdf:RDF>";
_rdfModel2AsString = @"<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:j.0="http://www.OBFUSCATED1.com/2013/05/OBFUSCATED7#"
xmlns:owl="http://www.w3.org/2002/07/owl#"
xmlns="http://www.OBFUSCATED1.com/2013/05/OBFUSCATED2#"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:mo="http://purl.org/ontology/mo/">
<rdf:Description rdf:about="http://www.OBFUSCATED4.com/veranstaltungen/uebersicht/veranstaltung-details/event/201305221830/OBFUSCATED9/">
<rdf:type rdf:resource="http://www.w3.org/2000/01/rdf-schema#Resource"/>
<rdf:type rdf:resource="http://www.OBFUSCATED1.com/2013/05/OBFUSCATED7#CalendarEvent"/>
<j.0:eventId>cbd3mghbgas8juuh4l88rt04ec</j.0:eventId>
<j.0:hasOrganization rdf:resource="http://www.OBFUSCATED1.com/2013/05/OBFUSCATED3#OBFUSCATED3"/>
<j.0:hasLocation rdf:resource="http://www.OBFUSCATED1.com/2013/05/OBFUSCATED3#Konzertsaal"/>
</rdf:Description>
</rdf:RDF>";
[super setUp];
}
- (void)tearDown
{
librdf_free_node(_obfuscated8EventIdProperty);
librdf_free_node(_obfuscated8CalendarEventIndividual);
librdf_free_uri(_obfuscated8NamespaceUri);
librdf_free_node(_rdfTypeProperty);
librdf_free_uri(_baseUri);
librdf_free_parser(_rdfParser);
librdf_free_storage(_rdfStorage);
librdf_free_world(_rdfWorld);
[super tearDown];
}
@end
//
// RdfModelWrapper.h
//
#import "librdf.h"
@interface RdfModelWrapper : NSObject
@property (assign, readonly) librdf_model *rdfModel;
- (id)initWithRdfModel:(librdf_model *)rdfModel;
@end
//
// RdfModelWrapper.m
//
#import "RdfModelWrapper.h"
@implementation RdfModelWrapper
- (id)initWithRdfModel:(librdf_model *)rdfModel
{
self = [super init];
if (self) {
_rdfModel = rdfModel; // RDFModelWrapper effectively takes ownership of rdfModel, i.e. is in charge of freeing it
}
return self;
}
- (void)dealloc
{
librdf_free_model(_rdfModel);
}
@end
librdf模型由存储支持。您的两个模型都由相同的memory
存储支持,因此包含相同的数据,即使模型实例不同。
您还使用查询函数librdf_model_get_source()
和librdf_model_get_target()
,它们只返回第一个匹配(如果有的话),而不是返回librdf_iterator
中所有匹配语句的函数,例如librdf_model_get_sources()
, librdf_model_get_targets()
或通用librdf_model_find_statements()
。这就是为什么所有查询都返回相同的节点。
所以,如果你想在不同的模型上工作,确保它们的后台存储也是不同的。
(我记得dajobe有一些理由保持模型和存储分开,但不记得是什么)