4

我正在比较两个图表,一个来自带有简单文字对象的 Turtle 文件,另一个来自具有显式数据类型 IRI 的文件。这些图在其他方面是相等的。

图A:

<s> <p> "o"

图B:

<s> <p> "o"^^xsd:string

根据RDF 1.1 (3.3 Literals),“[s]imple literals 是数据类型为 IRI http://www.w3.org/2001/XMLSchema#string的抽象语法文字的语法糖。这也反映在具体的语法规范中(N-TriplesTurtleRDF XML)。

因此,我希望我的两个图表都包含一个带有 URI 节点s主题、一个 URI 节点p谓词和一个带有xsd:string对象类型的文字节点o的三元组。基于此,我希望两者之间没有区别。

然而,实际情况并非如此:

var graphStringA = "<http://example.com/subject> <http://example.com/predicate> \"object\".";
var graphStringB = "<http://example.com/subject> <http://example.com/predicate> \"object\"^^<http://www.w3.org/2001/XMLSchema#string>.";

var graphA = new Graph();
var graphB = new Graph();

StringParser.Parse(graphA, graphStringA);
StringParser.Parse(graphB, graphStringB);

var diff = graphA.Difference(graphB);

差异报告中有一个添加和一个删除的三元组。图表不同,因为对象节点的数据类型不同:graphA.Triples.First().Object.Datatype什么都没有,而graphB.Triples.First().Object.DatatypeURI 是正确的。


在我看来,要修改这种行为,我必须要么

  • 一直到LiteralNode(并改变它对文字节点的假设),或者
  • 创建一个新的GraphDiff(考虑到字符串文字的默认数据类型)。

一种解决方法是删除“默认”数据类型:

private static void RemoveDefaultDatatype(IGraph g)
{
    var triplesWithDefaultDatatype =
        from triple in g.Triples
        where triple.Object is ILiteralNode
        let literal = triple.Object as ILiteralNode
        where literal.DataType != null
        where literal.DataType.AbsoluteUri == "http://www.w3.org/2001/XMLSchema#string" || literal.DataType.AbsoluteUri == "http://www.w3.org/2001/XMLSchema#langString"
        select triple;

    var triplesWithNoDatatype =
        from triple in triplesWithDefaultDatatype
        let literal = triple.Object as ILiteralNode
        select new Triple(
            triple.Subject,
            triple.Predicate,
            g.CreateLiteralNode(
                literal.Value,
                literal.Language));

    g.Assert(triplesWithNoDatatype.ToArray());
    g.Retract(triplesWithDefaultDatatype);
}

dotnetrdf 中是否有一种方法可以以与 RDF 1.1 一致的方式将简单文字与类型化文字进行比较,而无需采用上述主要重写或解决方法?

4

2 回答 2

3

根据 RobV 的回答使用 Handlers API:

class StripStringHandler : BaseRdfHandler, IWrappingRdfHandler
{
    protected override bool HandleTripleInternal(Triple t)
    {
        if (t.Object is ILiteralNode)
        {
            var literal = t.Object as ILiteralNode;

            if (literal.DataType != null && (literal.DataType.AbsoluteUri == "http://www.w3.org/2001/XMLSchema#string" || literal.DataType.AbsoluteUri == "http://www.w3.org/2001/XMLSchema#langString"))
            {
                var simpleLiteral = this.CreateLiteralNode(literal.Value, literal.Language);

                t = new Triple(t.Subject, t.Predicate, simpleLiteral);
            }
        }

        return this.handler.HandleTriple(t);
    }

    private IRdfHandler handler;

    public StripStringHandler(IRdfHandler handler) : base(handler)
    {
        this.handler = handler;
    }

    public IEnumerable<IRdfHandler> InnerHandlers
    {
        get
        {
            return this.handler.AsEnumerable();
        }
    }

    protected override void StartRdfInternal()
    {
        this.handler.StartRdf();
    }

    protected override void EndRdfInternal(bool ok)
    {
        this.handler.EndRdf(ok);
    }

    protected override bool HandleBaseUriInternal(Uri baseUri)
    {
        return this.handler.HandleBaseUri(baseUri);
    }

    protected override bool HandleNamespaceInternal(string prefix, Uri namespaceUri)
    {
        return this.handler.HandleNamespace(prefix, namespaceUri);
    }

    public override bool AcceptsAll
    {
        get
        {
            return this.handler.AcceptsAll;
        }
    }
}

用法:

class Program
{
    static void Main()
    {
        var graphA = Load("<http://example.com/subject> <http://example.com/predicate> \"object\".");
        var graphB = Load("<http://example.com/subject> <http://example.com/predicate> \"object\"^^<http://www.w3.org/2001/XMLSchema#string>.");

        var diff = graphA.Difference(graphB);

        Debug.Assert(diff.AreEqual);
    }

    private static IGraph Load(string source)
    {
        var result = new Graph();
        var graphHandler = new GraphHandler(result);
        var strippingHandler = new StripStringHandler(graphHandler);
        var parser = new TurtleParser();

        using (var reader = new StringReader(source))
        {
            parser.Load(strippingHandler, reader);
        }

        return result;
    }
}
于 2016-10-14T18:21:49.607 回答
3

dotNetRDF 不符合 RDF 1.1,我们也不声称是。有一个分支被重写以符合要求,但它还没有准备好远程生产。

假设您控制解析过程,您可以使用RDF 处理程序 API自定义对传入数据的处理。然后,您可以通过根据需要覆盖该方法,xsd:string在文本进入系统时将隐式类型从文本中剥离出来。HandleTriple(Triple t)

于 2016-10-14T13:30:31.263 回答