如何使用RDFLib解析.ttl文件?
我有一个文件,格式是.ttl
。里面有4个属性/列,包含了四元组,格式如下:
(id, 学生姓名, 学生地址, 学生电话)
。(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 个回答
你可以按照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
看起来从rdflib 5.0.0版本开始,turtle格式是被支持的。我做了
from rdflib import Graph
graph = Graph()
graph.parse('myfile.ttl', format='ttl')
这个解析得很好。
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')