如何比较 dotnetrdf 中的简单文字和类型文字?
How to compare simple and typed literals in dotnetrdf?
我正在比较两个图表,一个来自具有简单文字对象的 Turtle 文件,另一个来自具有显式数据类型 IRI 的文件。这些图在其他方面是相等的。
图 A:
<s> <p> "o"
图 B:
<s> <p> "o"^^xsd:string
根据RDF 1.1 (3.3 Literals), "[s]imple literals are syntactic sugar for abstract syntax literals with the datatype IRI http://www.w3.org/2001/XMLSchema#string". This is reflected in the concrete syntax specifications as well (N-Triples, Turtle, RDF 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.Datatype
是正确的 URI。
在我看来,要修改此行为我必须
- 一直向下到 LiteralNode(并改变其对文字节点的假设),或者
- 创建一个新的 GraphDiff(将字符串文字的默认数据类型考虑在内)。
解决方法是删除 "default" 数据类型:
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 的方式将简单文字与类型化文字进行比较,而无需像上面那样诉诸重大重写或解决方法?
dotNetRDF 不符合 RDF 1.1,我们也未声称符合。有一个分支被重写为兼容,但它不是远程生产就绪的。
假设您控制解析过程,您可以使用 RDF Handlers API 自定义传入数据的处理。然后,您可以根据需要覆盖 HandleTriple(Triple t)
方法,从而在隐式 xsd:string
类型文字进入系统时将其剥离。
根据 RobV 的回答使用处理程序 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;
}
}
我正在比较两个图表,一个来自具有简单文字对象的 Turtle 文件,另一个来自具有显式数据类型 IRI 的文件。这些图在其他方面是相等的。
图 A:
<s> <p> "o"
图 B:
<s> <p> "o"^^xsd:string
根据RDF 1.1 (3.3 Literals), "[s]imple literals are syntactic sugar for abstract syntax literals with the datatype IRI http://www.w3.org/2001/XMLSchema#string". This is reflected in the concrete syntax specifications as well (N-Triples, Turtle, RDF 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.Datatype
是正确的 URI。
在我看来,要修改此行为我必须
- 一直向下到 LiteralNode(并改变其对文字节点的假设),或者
- 创建一个新的 GraphDiff(将字符串文字的默认数据类型考虑在内)。
解决方法是删除 "default" 数据类型:
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 的方式将简单文字与类型化文字进行比较,而无需像上面那样诉诸重大重写或解决方法?
dotNetRDF 不符合 RDF 1.1,我们也未声称符合。有一个分支被重写为兼容,但它不是远程生产就绪的。
假设您控制解析过程,您可以使用 RDF Handlers API 自定义传入数据的处理。然后,您可以根据需要覆盖 HandleTriple(Triple t)
方法,从而在隐式 xsd:string
类型文字进入系统时将其剥离。
根据 RobV 的回答使用处理程序 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;
}
}