我有一个.ttl
形式的文件。它有4个属性/列,包含以下形式的四元组:
(id, student_name, student_address, student_phoneno)
。 (id, faculty_name, faculty_address, faculty_phoneno)
。我知道如何用RDFLib解析.n3
格式三元组;
from rdflib import Graph
g = Graph()
g.parse("demo.nt", format="nt")
但我不确定如何解析这些四重奏。
我的目的是解析并提取与特定id有关的所有信息。学生和教师的身份证可以相同。
如何使用RDFLib处理这些四元组并将其用于基于id
的聚合?
来自.ttl
文件的示例摘录:
#@ <id1>
<Alice> <USA> <12345>
#@ <id1>
<Jane> <France> <78900>
答案 0 :(得分:8)
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')
将条目保存到db:
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')
答案 1 :(得分:1)
看起来至少从 rdflib 5.0.0 开始支持turtle。我做过
from rdflib import Graph
graph = Graph()
graph.parse('myfile.ttl', format='ttl')
这解析得很好。
答案 2 :(得分:0)
目前似乎没有这样的库来解析Turtle - Terse RDF Triple Language
正如您已经知道的语法,最好的办法是使用PyParsing首先创建一个语法然后解析文件。
我还建议根据您的需要调整以下EBNF implementation
答案 3 :(得分:0)
你可以像Snakes和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()
得到一个dict解析的行,你可以一次神奇地得到一行 - 不会涉及额外的RAM抖动。
如果您有16个原始数据,您可以考虑使用生成器来拉入线路。他们真的很有用。
有关SO和某些文档的生成器的更多信息: What can you use Python generator functions for? http://wiki.python.org/moin/Generators