1

我现在已经隔离了我之前也询问过的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
4

1 回答 1

1

librdf 模型由存储支持。您的两个模型都由相同的memory存储支持,因此包含相同的数据,即使模型实例不同。

您还使用了查询函数librdf_model_get_source()librdf_model_get_target()并且只返回第一个匹配项(如果有),而不是返回 a 中所有匹配语句的函数,librdf_iterator例如或 generic 。这就是为什么您会为所有查询返回相同的节点。librdf_model_get_sources()librdf_model_get_targets()librdf_model_find_statements()

因此,如果您想处理不同的模型,请确保它们的后备存储也不同。

(我记得 dajobe 有一些理由将模型和存储分开,但不记得是什么了。)

于 2013-06-02T20:16:22.537 回答