【问题标题】:Accessing RDF/XML/OWL file nodes using Perl使用 Perl 访问 RDF/XML/OWL 文件节点
【发布时间】:2013-07-16 20:59:23
【问题描述】:

我有一个想要解析和访问节点的 RDF/XML 数据。 它看起来像这样:

<!-- http://purl.obolibrary.org/obo/VO_0000185 -->

    <owl:Class rdf:about="&obo;VO_0000185">
        <rdfs:label>Influenza virus gene</rdfs:label>
        <rdfs:subClassOf rdf:resource="&obo;VO_0000156"/>
        <obo:IAO_0000117>YH</obo:IAO_0000117>
    </owl:Class>



    <!-- http://purl.obolibrary.org/obo/VO_0000186 -->

    <owl:Class rdf:about="&obo;VO_0000186">
        <rdfs:label>RNA vaccine</rdfs:label>
        <owl:equivalentClass>
            <owl:Class>
                <owl:intersectionOf rdf:parseType="Collection">
                    <rdf:Description rdf:about="&obo;VO_0000001"/>
                    <owl:Restriction>
                        <owl:onProperty rdf:resource="&obo;BFO_0000161"/>
                        <owl:someValuesFrom rdf:resource="&obo;VO_0000728"/>
                    </owl:Restriction>
                </owl:intersectionOf>
            </owl:Class>
        </owl:equivalentClass>
        <rdfs:subClassOf rdf:resource="&obo;VO_0000001"/>
        <obo:IAO_0000116>Using RNA may eliminate the problem of having to tailor a vaccine for each individual patient with their specific immunity. The advantage of RNA is that it can be used for all immunity types and can be taken from a single cell. DNA vaccines need to produce RNA which then prompts the manufacture of proteins. However, RNA vaccine eliminates the step from DNA to RNA.</obo:IAO_0000116>
        <obo:IAO_0000115>A vaccine that uses RNA(s) derived from a pathogen organism.</obo:IAO_0000115>
        <obo:IAO_0000117>YH</obo:IAO_0000117>
    </owl:Class>

完整的RDF/XML文件可以在here找到。

我想做的是做以下事情:

  1. 找到包含条目&lt;rdfs:subClassOf rdf:resource="&amp;obo;VO_0000001"/&gt;的块
  2. 访问由&lt;rdfs:label&gt;...&lt;/rdfs:label&gt; 定义的字面术语

所以在上面的例子中,代码将通过第二个块并输出: “RNA疫苗”。

我目前坚持使用以下代码。我做不到的地方 访问节点。正确的方法是什么?使用 XML::LibXML 以外的解决方案 受到欢迎。

#!/usr/bin/perl -w
use strict;
use Data::Dumper;
use Carp;
use File::Basename;
use XML::LibXML 1.70;

my $filename = "VO.owl";
# Obtained from http://svn.code.sf.net/p/vaccineontology/code/trunk/src/ontology/VO.owl

my $parser = XML::LibXML->new();
my $doc = $parser->parse_file( $filename );

foreach my $chunk ($doc->findnodes('/owl:Class')) {
        my ($label) = $chunk->findnodes('./rdfs:label');
        my ($subclass) = $chunk->findnodes('./rdfs:subClassOf');
        print $label->to_literal;
        print $subclass->to_literal;

}

【问题讨论】:

  • 我要提一下,不使用 XML 库的解决方案不仅应该受到欢迎,而且首选don't try to parse RDF as XML。诚然,RDF 可以在 XML 中序列化,但是同样的 RDF 图可以在 XML 中以许多不同的方式进行序列化,并且适用于其中一种的 XML 解决方案不太可能适用于另一种。 RDF 是基于图的表示,应该这样对待。

标签: xml perl parsing rdf cpan


【解决方案1】:

像解析 XML 一样解析 RDF 是愚蠢的。完全相同的数据可以以许多不同的方式出现。例如,以下所有 RDF 文件都携带相同的数据。任何符合标准的 RDF 实现必须以相同的方式处理它们...

<!-- example 1 -->
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
  <rdf:Description rdf:about="#me">
    <rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person" />
    <foaf:name>Toby Inkster</foaf:name>
  </rdf:Description>
</rdf:RDF>

<!-- example 2 -->
<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:foaf="http://xmlns.com/foaf/0.1/">
  <foaf:Person rdf:about="#me">
    <foaf:name>Toby Inkster</foaf:name>
  </foaf:Person>
</rdf:RDF>

<!-- example 3 -->
<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:foaf="http://xmlns.com/foaf/0.1/">
  <foaf:Person rdf:about="#me" foaf:name="Toby Inkster" />
</rdf:RDF>

<!-- example 4 -->
<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:foaf="">
  <rdf:Description rdf:about="#me"
    rdf:type="http://xmlns.com/foaf/0.1/Person"
    foaf:name="Toby Inkster" />
</rdf:RDF>

<!-- example 5 -->
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
  <rdf:Description rdf:ID="me">
    <rdf:type>
      <rdf:Description rdf:about="http://xmlns.com/foaf/0.1/Person" />
    </rdf:type>
    <foaf:name>Toby Inkster</foaf:name>
  </rdf:Description>
</rdf:RDF>

<!-- example 6 -->
<foaf:Person
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:foaf="http://xmlns.com/foaf/0.1/"
    rdf:about="#me"
    foaf:name="Toby Inkster" />

我也可以轻松列出六种其他变体,但我会就此打住。而这个 RDF 文件只包含两个语句——我是一个人;我的名字是“Toby Inkster”——OP 的数据包含超过 50,000 条语句。

这只是RDF的XML序列化;还有其他的序列化。

如果您尝试使用 XPath 处理所有这些,您最终可能会变成一个被锁在某处塔楼中的疯子,在睡梦中喃喃自语关于三元组的事情;三元组...

幸运的是,格雷格·威廉姆斯已经为您解决了心理健康问题。 RDF::TrineRDF::Query 不仅是 Perl 的最佳 RDF 框架;它们是所有编程语言中最好的。

以下是如何使用 RDF::Trine 和 RDF::Query 来完成 OP 的任务:

#!/usr/bin/env perl

use v5.12;
use RDF::Trine;
use RDF::Query;

my $model = 'RDF::Trine::Model'->new(
    'RDF::Trine::Store::DBI'->new(
        'vo',
        'dbi:SQLite:dbname=/tmp/vo.sqlite',
        '',  # no username
        '',  # no password
    ),
);

'RDF::Trine::Parser::RDFXML'->new->parse_url_into_model(
    'http://svn.code.sf.net/p/vaccineontology/code/trunk/src/ontology/VO.owl',
    $model,
) unless $model->size > 0;

my $query = RDF::Query->new(<<'SPARQL');
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT ?super_label ?sub_label
WHERE {
    ?sub rdfs:subClassOf ?super .
    ?sub rdfs:label ?sub_label .
    ?super rdfs:label ?super_label .
}
LIMIT 5
SPARQL

print $query->execute($model)->as_string;

示例输出:

+----------------------------+----------------------------------+
| super_label                | sub_label                        |
+----------------------------+----------------------------------+
| "Aves vaccine"             | "Ducks vaccine"                  |
| "route of administration"  | "intravaginal route"             |
| "Shigella gene"            | "aroA from Shigella"             |
| "Papillomavirus vaccine"   | "Bovine papillomavirus vaccine"  |
| "virus protein"            | "Feline leukemia virus protein"  |
+----------------------------+----------------------------------+

更新:这是一个 SPARQL 查询,可以插入到上面的脚本中以检索您想要的数据:

PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX obo:  <http://purl.obolibrary.org/obo/>
SELECT ?subclass ?label
WHERE {
    ?subclass
        rdfs:subClassOf obo:VO_0000001 ;
        rdfs:label ?label .
}

【讨论】:

  • 感谢您的解释。我通常会尽量远离 XML,并且我会特别避免使用一些 XML 技术(例如 XSD、SOAP)——RDF 将被添加到此列表中 :-)
  • 您当然不应该将 RDF 添加到您希望避免的 XML 技术列表中。如果您愿意,请避免使用它;美好的。但是(尽管有 XML 序列化)它不是一种 XML 技术,所以你会把它放在错误的列表中。
  • @tobyink:谢谢。但是如何确保标签输出是 VO_0000001 的子类。
【解决方案2】:

查看perlrdf.org 网站,其中包含许多用于使用 RDF 的 Perl 包的链接。

使用这些可能比使用 XPath 访问 RDF/XML 更灵活,更不容易出错,因为 RDF/XML 不是规范化的序列化,即相同的数据可以用不同的 XML 形式表示,具体取决于用于序列化它的工具.

【讨论】:

    【解决方案3】:

    /owl:Class 不是 XML 文档中的根元素。您必须在 XPath 中包含根元素:/rdf:RDF/owl:Class。或者,如果您想获取所有匹配项,无论 XML 树的深度如何,都可以使用双斜杠表示法://owl:Class

    【讨论】:

    • 谢谢奴隶。但我无法访问“subClassOf”内容。什么是正确的命令?
    • 您可以访问 subClassOf。但它没有文字值(这是标签之间的文本内容,因此它显示为空字符串。而不是to_literal() 尝试serialize 以查看它是否匹配。
    • @neversaint 你的意思是什么子类内容?在您所说的问题中,您试图访问类的 rdfs:label 属性的值,然后还要识别类的 owl:subClassOf 属性的值。您想从子类中获取什么内容?
    • 真的,真的,忘记用 XPath 来解析 RDF。使用RDF::Trine,也可能使用RDF::Query
    • 解释长于评论,但我很乐意提供完整的答案。来了……
    猜你喜欢
    • 2013-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-31
    • 2011-05-30
    • 1970-01-01
    • 1970-01-01
    • 2013-02-19
    相关资源
    最近更新 更多