3

对于像这样的一些 RDF:

<?xml version="1.0"?>
<rdf:RDF
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:blah="http://www.something.org/stuff#">
<rdf:Description rdf:about="http://www.something.org/stuff/some_entity1">
<blah:stringid>string1</blah:stringid>
<blah:uid>1</blah:uid>
<blah:myitems rdf:parseType="Collection">
  <blah:myitem>
        <blah:myitemvalue1>7</blah:myitemvalue1>
        <blah:myitemvalue2>8</blah:myitemvalue2>
     </blah:myitem>
...
    <blah:myitem>
     <blah:myitemvalue1>7</blah:myitemvalue1>
        <blah:myitemvalue2>8</blah:myitemvalue2>
    </blah:myitem>
</blah:myitems>
</rdf:Description>

<rdf:Description rdf:about="http://www.something.org/stuff/some__other_entity2">
<blah:stringid>string2</blah:stringid>
<blah:uid>2</blah:uid>
<blah:myitems rdf:parseType="Collection">
    <blah:myitem>
        <blah:myitemvalue1>7</blah:myitemvalue1>
        <blah:myitemvalue2>8</blah:myitemvalue2>
     </blah:myitem>
....
    <blah:myitem>
        <blah:myitemvalue1>7</blah:myitemvalue1>
        <blah:myitemvalue2>8</blah:myitemvalue2>
    </blah:myitem>
</blah:myitems>
</rdf:Description>
</rdf:RDF>

我正在使用 Jena/SPARQL,我希望能够使用 SELECT 查询来检索myitems具有特定实体的节点,stringid然后从结果集中提取它并遍历并获取每个myitem节点的值。顺序并不重要。

所以我有两个问题:

  1. 我需要在我的查询中指定blah:myitems一个列表吗?
  2. 如何解析 ResultSet 中的列表?
4

1 回答 1

10

在 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:firstrdf: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 );
            }
        }
    }
}
于 2013-07-17T12:07:26.490 回答