在 SPARQL 中选择列表(和元素)
让我们首先解决 SPARQL 问题。我稍微修改了您的数据,使元素具有不同的值,因此在输出中更容易看到它们。这是 N3 格式的数据,更简洁一些,尤其是在表示列表时:
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix blah: <http://www.something.org/stuff#> .
<http://www.something.org/stuff/some_entity1>
blah:myitems ([ a blah:myitem ;
blah:myitemvalue1 "1" ;
blah:myitemvalue2 "2"
] [ a blah:myitem ;
blah:myitemvalue1 "3" ;
blah:myitemvalue2 "4"
]) ;
blah:stringid "string1" ;
blah:uid "1" .
<http://www.something.org/stuff/some__other_entity2>
blah:myitems ([ a blah:myitem ;
blah:myitemvalue1 "5" ;
blah:myitemvalue2 "6"
] [ a blah:myitem ;
blah:myitemvalue1 "7" ;
blah:myitemvalue2 "8"
]) ;
blah:stringid "string2" ;
blah:uid "2" .
myitems
您在选择节点的问题中提到,但myitems
实际上是将实体与列表相关联的属性。您可以在 SPARQL 中选择属性,但我猜您实际上想要选择列表的头部,即myitems
属性的值。这很简单。您不需要指定它是一个rdf:List
,但如果 的值myitems
也可能是一个非列表,那么您应该指定您只是在寻找rdf:Lists
. (为了开发 SPARQL 查询,我将使用 Jena 的 ARQ 命令行工具运行它们,因为之后我们可以很容易地将它们移动到 Java 代码中。)
prefix blah: <http://www.something.org/stuff#>
select ?list where {
[] blah:myitems ?list .
}
$ arq --data data.n3 --query items.sparql
--------
| list |
========
| _:b0 |
| _:b1 |
--------
列表的头部是空白节点,所以这是我们期望的结果。从这些结果中,您可以从结果集中获取资源,然后开始遍历列表,但由于您不关心列表中节点的顺序,您不妨在 SPARQL 查询中选择它们,然后遍历结果集,得到每一项。您似乎也可能对要检索其项目的实体感兴趣,因此该查询也在此查询中。
prefix blah: <http://www.something.org/stuff#>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
select ?entity ?list ?item ?value1 ?value2 where {
?entity blah:myitems ?list .
?list rdf:rest* [ rdf:first ?item ] .
?item a blah:myitem ;
blah:myitemvalue1 ?value1 ;
blah:myitemvalue2 ?value2 .
}
order by ?entity ?list
$ arq --data data.n3 --query items.sparql
----------------------------------------------------------------------------------------
| entity | list | item | value1 | value2 |
========================================================================================
| <http://www.something.org/stuff/some__other_entity2> | _:b0 | _:b1 | "7" | "8" |
| <http://www.something.org/stuff/some__other_entity2> | _:b0 | _:b2 | "5" | "6" |
| <http://www.something.org/stuff/some_entity1> | _:b3 | _:b4 | "3" | "4" |
| <http://www.something.org/stuff/some_entity1> | _:b3 | _:b5 | "1" | "2" |
----------------------------------------------------------------------------------------
通过按实体和列表对结果进行排序(如果某个实体具有多个myitems
属性值),您可以遍历结果集并确保按顺序获取实体列表中的所有元素。由于您的问题是关于结果集中的列表,而不是关于如何使用结果集,我假设迭代结果不是问题。
在 Jena 中使用列表
以下示例展示了如何在 Java 中使用列表。代码的第一部分只是加载模型和运行 SPARQL 查询的样板。获取查询结果后,您可以将资源视为链表的头部并使用rdf:first
和rdf:rest
属性手动迭代,或者您可以将资源强制转换为 JenaRDFList
并从中获取迭代器。
import java.io.IOException;
import java.io.InputStream;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.RDFList;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.util.iterator.ExtendedIterator;
import com.hp.hpl.jena.vocabulary.RDF;
public class SPARQLListExample {
public static void main(String[] args) throws IOException {
// Create a model and load the data
Model model = ModelFactory.createDefaultModel();
try ( InputStream in = SPARQLListExample.class.getClassLoader().getResourceAsStream( "SPARQLListExampleData.rdf" ) ) {
model.read( in, null );
}
String blah = "http://www.something.org/stuff#";
Property myitemvalue1 = model.createProperty( blah + "myitemvalue1" );
Property myitemvalue2 = model.createProperty( blah + "myitemvalue2" );
// Run the SPARQL query and get some results
String getItemsLists = "" +
"prefix blah: <http://www.something.org/stuff#>\n" +
"\n" +
"select ?list where {\n" +
" [] blah:myitems ?list .\n" +
"}";
ResultSet results = QueryExecutionFactory.create( getItemsLists, model ).execSelect();
// For each solution in the result set
while ( results.hasNext() ) {
QuerySolution qs = results.next();
Resource list = qs.getResource( "list" ).asResource();
// Once you've got the head of the list, you can either process it manually
// as a linked list, using RDF.first to get elements and RDF.rest to get
// the rest of the list...
for ( Resource curr = list;
!RDF.nil.equals( curr );
curr = curr.getRequiredProperty( RDF.rest ).getObject().asResource() ) {
Resource item = curr.getRequiredProperty( RDF.first ).getObject().asResource();
RDFNode value1 = item.getRequiredProperty( myitemvalue1 ).getObject();
RDFNode value2 = item.getRequiredProperty( myitemvalue2 ).getObject();
System.out.println( item+" has:\n\tvalue1: "+value1+"\n\tvalue2: "+value2 );
}
// ...or you can make it into a Jena RDFList that can give you an iterator
RDFList rdfList = list.as( RDFList.class );
ExtendedIterator<RDFNode> items = rdfList.iterator();
while ( items.hasNext() ) {
Resource item = items.next().asResource();
RDFNode value1 = item.getRequiredProperty( myitemvalue1 ).getObject();
RDFNode value2 = item.getRequiredProperty( myitemvalue2 ).getObject();
System.out.println( item+" has:\n\tvalue1: "+value1+"\n\tvalue2: "+value2 );
}
}
}
}