如何使用RDFLib解析.ttl文件?

14 投票
4 回答
24172 浏览
提问于 2025-04-17 17:40

我有一个文件,格式是.ttl。里面有4个属性/列,包含了四元组,格式如下:

  1. (id, 学生姓名, 学生地址, 学生电话)
  2. (id, 教师姓名, 教师地址, 教师电话)

我知道怎么用RDFLib来解析.n3格式的三元组;

from rdflib import Graph
g = Graph()
g.parse("demo.nt", format="nt")

但是我不太确定怎么解析这些四元组。

我的目的是解析并提取与特定id相关的所有信息。这个id在学生和教师中可能是相同的。

我该如何使用RDFLib来处理这些四元组,并根据id进行汇总呢?

这是.ttl文件中的一个示例片段:

#@ <id1>
<Alice> <USA> <12345>

#@ <id1>
<Jane> <France> <78900>

4 个回答

0

你可以按照Snakes and Coffee的建议,把那个函数(或者它的代码)放在一个循环里,并加上yield语句。这样就能创建一个生成器,可以逐步调用它来动态生成下一行的字典。如果你打算把这些数据写入csv文件,比如使用Snakes的parse_to_dict:

import re
import csv

writer = csv.DictWriter(open(outfile, "wb"), fieldnames=["id", "name", "address", "phone"])
# or whatever

你可以通过一个函数或者用内联的方式来创建一个生成器:

def dict_generator(lines): 
    for line in lines: 
        yield parse_to_dict(line)

--或者--

dict_generator = (parse_to_dict(line) for line in lines)

这两种方式基本上是一样的。到这个时候,你可以通过调用 dict_generator.next() 来获取一个字典格式的行数据,神奇的是,它会一个一个地给你返回,而不会占用额外的内存。

如果你有16GB的原始数据,考虑使用生成器来逐行读取数据也是个好主意。生成器真的很有用。

关于生成器的更多信息,可以参考SO和一些文档: 你可以用Python生成器函数做什么? http://wiki.python.org/moin/Generators

6

看起来从rdflib 5.0.0版本开始,turtle格式是被支持的。我做了

from rdflib import Graph
graph = Graph()
graph.parse('myfile.ttl', format='ttl')

这个解析得很好。

14

Turtle 是一种简化的 Notation 3 语法,所以 rdflib 应该可以用 format='n3' 来解析它。你可以检查一下 rdflib 是否能保留注释(在你的示例中,注释里有 #...id)。如果不能,而且输入格式像你示例中那样简单的话,你可以手动解析它:

import re
from collections import namedtuple
from itertools import takewhile

Entry = namedtuple('Entry', 'id name address phone')

def get_entries(path):
    with open(path) as file:
        # an entry starts with `#@` line and ends with a blank line
        for line in file:
            if line.startswith('#@'):
                buf = [line]
                buf.extend(takewhile(str.strip, file)) # read until blank line
                yield Entry(*re.findall(r'<([^>]+)>', ''.join(buf)))

print("\n".join(map(str, get_entries('example.ttl'))))

输出结果:

Entry(id='id1', name='Alice', address='USA', phone='12345')
Entry(id='id1', name='Jane', address='France', phone='78900')

要把数据保存到数据库:

import sqlite3

with sqlite3.connect('example.db') as conn:
    conn.execute('''CREATE TABLE IF NOT EXISTS entries
             (id text, name text, address text, phone text)''')
    conn.executemany('INSERT INTO entries VALUES (?,?,?,?)',
                     get_entries('example.ttl'))

如果你需要在 Python 中进行一些后处理,可以按 id 分组:

import sqlite3
from itertools import groupby
from operator import itemgetter

with sqlite3.connect('example.db') as c:
    rows = c.execute('SELECT * FROM entries ORDER BY id LIMIT ?', (10,))
    for id, group in groupby(rows, key=itemgetter(0)):
        print("%s:\n\t%s" % (id, "\n\t".join(map(str, group))))

输出结果:

id1:
    ('id1', 'Alice', 'USA', '12345')
    ('id1', 'Jane', 'France', '78900')

撰写回答