甜RDF / quick-rdf-io
与甜RDF/rdfInterface 兼容的解析器和序列化器集合
Requires
- php: >=8.0
- ext-mbstring: *
- ext-pcre: *
- ext-xmlreader: *
- ml/json-ld: ^1.2
- pietercolpaert/hardf: >=0.3.1 <1
- sweetrdf/rdf-helpers: ^2
- sweetrdf/rdf-interface: ^2
- zozlak/rdf-constants: ^1.1
Requires (Dev)
- php-coveralls/php-coveralls: ^2.4
- phpstan/phpstan: ^1
- phpunit/phpunit: ^10
- sweetrdf/quick-rdf: ^2
- sweetrdf/simple-rdf: ^2
- sweetrdf/term-templates: ^2.0.2
Suggests
This package is auto-updated.
Last update: 2024-09-14 19:56:40 UTC
README
RDF解析器和序列化器集合,实现https://github.com/sweetrdf/rdfInterface 接口。
最初为 quickRdf 库开发。
支持的格式
[1] 流式解析器/序列化器不会在内存中完全实现整个数据集,这保证了恒定(且低)的内存占用。(此功能仅适用于解析器/序列化器 - 请参阅下面的内存使用部分)
[2] 使用 jsonld-stream
作为 \quickRdfIo\Util::serialize()
的 $format
参数值来使用此序列化器。
[3] 仅以极度扁平化的Json-LD格式输出数据,但以流式模式运行。
安装
- 获取 Composer
- 运行
composer require sweetrdf/quick-rdf-io
自动生成的文档
https://sweetrdf.github.io/quickRdfIo/namespaces/quickrdfio.html
它非常不完整,但没有比什么都没有好。
包括 RdfInterface 和 ml/json-ld 文档。
使用方法
注意 - 示例中调用了两个其他库 sweetrdf/quick-rdf 和 sweetrdf/term-templates。您可以使用 composer require sweetrdf/quick-rdf
和 composer require sweetrdf/term-templates
来安装它们。
基本解析
只需使用 \quickRdfIo\Util::parse($input, $dataFactory, $format, $baseUri)
,其中
$input
可以是(几乎)包含RDF的“任何东西”(一个RDF字符串,文件的路径,URL,打开的资源(fopen()
的结果),PSR-7响应或PSR-7 StreamInterface对象)。$dataFactory
是实现\rdfInterface\DataFactory
接口的对象,例如new \quickRdf\DataFactory()
。$format
是一个 可选的 显式RDF格式指示,用于处理无法自动检测格式的罕见情况。请参阅src/quickRdfIo/Util.php::getParser()
源代码,查看所有接受的$format
值的列表。$baseUri
是一个 可选的 baseURI值(对于某些类型的$input
值,它可以自动检测)。
include 'vendor/autoload.php'; // create a DataFactory - it's needed by all parsers // (DataFactory implementation comes from other package, here sweetrdf/quick-rdf) $dataFactory = new \quickRdf\DataFactory(); // parse a file $iterator = \quickRdfIo\Util::parse('tests/files/quadsPositive.nq', $dataFactory); foreach ($iterator as $i) echo "$i\n"; // parse a remote file (with format autodetection as github wrongly reports text/html) $url = 'https://github.com/sweetrdf/quickRdfIo/raw/master/tests/files/spec2.10.rdf'; $iterator = \quickRdfIo\Util::parse($url, $dataFactory); foreach ($iterator as $i) echo "$i\n"; // parse a PSR-7 response (format recognized from the response content-type header) $url = 'https://www.w3.org/2000/10/rdf-tests/RDF-Model-Syntax_1.0/ms_7.2_1.rdf'; $client = new \GuzzleHttp\Client(); $request = new \GuzzleHttp\Psr7\Request('GET', $url); $response = $client->send($request); $iterator = \quickRdfIo\Util::parse($response, $dataFactory); foreach ($iterator as $i) echo "$i\n"; // parse a string containing RDF with format autodetection $rdf = file_get_contents('https://www.w3.org/2000/10/rdf-tests/RDF-Model-Syntax_1.0/ms_7.2_1.rdf'); $iterator = \quickRdfIo\Util::parse($rdf, $dataFactory); foreach ($iterator as $i) echo "$i\n"; // parse an PHP stream $stream = fopen('tests/files/quadsPositive.nq', 'r'); $iterator = \quickRdfIo\Util::parse($stream, $dataFactory); fclose($stream); // in most cases you will populate a Dataset with parsed triples/quads // (note that a Dataset implementation comes from other package, e.g. sweetrdf/quick-rdf) $dataset = new \quickRdf\Dataset(); $url = 'https://github.com/sweetrdf/quickRdfIo/raw/master/tests/files/spec2.10.rdf'; $dataset->add(\quickRdfIo\Util::parse($url, $dataFactory)); echo $dataset;
基本序列化
只需使用 \quickRdfIo\Util::serialize($data, $format, $output, $nmsp)
,其中
$data
是实现\rdfInterface\QuadIterator
接口的对象,例如一个Dataset或解析器返回的迭代器。$format
指定一个RDF序列化格式,例如turtle
或ntriples
。请参阅src/quickRdfIo/Util.php::getSeriazlier()
源代码,查看所有接受的$format
值的列表。$output
是一个 可选的 参数,描述输出应写入的位置。如果它缺失或为null,则输出作为字符串返回。如果它是一个字符串,则将其视为使用fopen($output, 'wb')
打开的路径。如果它是一个流资源或PSR-8StreamInterface
实例,则输出直接写入其中。$nmsp
是一个 可选 参数,用于向序列化器传递期望的 RDF 命名空间别名。注意,某些格式(如 n-triples 和 n-quads)不支持命名空间别名,而在其他格式(例如 turtle)中使用它们则非常常见。
include 'vendor/autoload.php'; $iterator = ...some \rdfInterface\QuadIterator, e.g. one from parsing examples... // serialize to file in text/turtle format \quickRdfIo\Util::serialize($iterator, 'turtle', 'myFile.ttl'); // serialize to string echo \quickRdfIo\Util::serialize($iterator, 'turtle'); // use given namespace aliases when serializing to turtle $nmsp = new \quickRdf\RdfNamespace(); $nmsp->add('http://purl.org/dc/terms/', 'dc'); $nmsp->add('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdf'); echo \quickRdfIo\Util::serialize($iterator, 'turtle', null, $nmsp);
基本转换
include 'vendor/autoload.php'; // create a DataFactory - it's needed by all parsers // (note that DataFactory implementation comes from other package, e.g. sweetrdf/quick-rdf) $dataFactory = new \quickRdf\DataFactory(); // or any other example from the "Basic parsing" section above $iterator = \quickRdfIo\Util::parse('tests/files/puzzle4d_100k.nt', $dataFactory); // or any other example from the "Basic serialization" section above \quickRdfIo\Util::serialize($iterator, 'rdf', 'output.rdf');
不带数据集的基本过滤
值得注意的是,基本的三元组/四元组过滤可以通过不使用数据集实现以内存高效的方式进行。
假设我们想要将 https://vocabs.acdh.oeaw.ac.at/schema#hasIdentifier
谓词的所有三元组从 test/files/puzzle4d_100k.nt
n-triples 文件复制到 ids.ttl
turtle 文件中。
典型的方法是将数据加载到数据集中,在那里过滤它们,最后序列化数据集
include 'vendor/autoload.php'; $dataFactory = new \quickRdf\DataFactory(); $t = microtime(true); // parse input into a Dataset $iterator = \quickRdfIo\Util::parse('tests/files/puzzle4d_100k.nt', $dataFactory); $dataset = new \quickRdf\Dataset(); $dataset->add($iterator); // filter out non-matching triples $template = new \termTemplates\QuadTemplate(null, $dataFactory->namedNode('https://vocabs.acdh.oeaw.ac.at/schema#hasIdentifier'), null); $dataset->deleteExcept($template); // serialize \quickRdfIo\Util::serialize($dataset, 'turtle', 'ids.ttl'); print_r([ 'time [s]' => microtime(true) - $t, 'memory [MB]' => (int) (memory_get_peak_usage(true) / 1024 / 1024), ]); // 4.4s, 125 MB of RAM
但也可以通过使用“过滤生成器”而不是数据集来完成。这种方法可以避免在内存中实例化整个数据集,这应该既会减少内存占用,也会略微提高速度
include 'vendor/autoload.php'; $dataFactory = new \quickRdf\DataFactory(); $t = microtime(true); // prepare input generator $iterator = \quickRdfIo\Util::parse('tests/files/puzzle4d_100k.nt', $dataFactory); // create a generator performing the filtering $template = new \termTemplates\QuadTemplate(null, $dataFactory->namedNode('https://vocabs.acdh.oeaw.ac.at/schema#hasIdentifier'), null); $filter = function($iter, $tmpl) { foreach ($iter as $quad) { if ($tmpl->equals($quad)) { yield $quad; } } }; // wrap it into something implementing \rdfInterface\QuadIterator for types compatibility $wrapper = new \rdfHelpers\GenericQuadIterator($filter($iterator, $template)); // serialize our filtering generator \quickRdfIo\Util::serialize($wrapper, 'turtle', 'ids.ttl'); print_r([ 'time [s]' => microtime(true) - $t, 'memory [MB]' => (int) (memory_get_peak_usage(true) / 1024 / 1024), ]); // 2.7s, 51 MB of RAM
结果更好,但内存占用仍然出奇的高。这是因为我们使用的 DataFactory 实现,以及它所应用的性能优化(诚实地讲,在我们的场景中这只会减慢速度)。我们可以通过使用尽可能简单的 DataFactory 实现来进一步优化(为此我们需要另一个包 - sweetrdf/simple-rdf
)
include 'vendor/autoload.php'; $dataFactory = new \simpleRdf\DataFactory(); $t = microtime(true); // prepare input generator $iterator = \quickRdfIo\Util::parse('tests/files/puzzle4d_100k.nt', $dataFactory); // create a generator performing the filtering $template = new \termTemplates\QuadTemplate(null, $dataFactory->namedNode('https://vocabs.acdh.oeaw.ac.at/schema#hasIdentifier'), null); $filter = function($iter, $tmpl) { foreach ($iter as $quad) { if ($tmpl->equals($quad)) { yield $quad; } } }; // wrap it into something implementing \rdfInterface\QuadIterator for types compatibility $wrapper = new \rdfHelpers\GenericQuadIterator($filter($iterator, $template)); // serialize our filtering generator \quickRdfIo\Util::serialize($wrapper, 'turtle', 'ids.ttl'); print_r([ 'time [s]' => microtime(true) - $t, 'memory [MB]' => (int) (memory_get_peak_usage(true) / 1024 / 1024), ]); // 1.9s, 2 MB of RAM
正如我们所见,优化后的实现比基于数据集的实现快2.3倍,内存占用降低了60倍。
注意
- 请查阅 sweetrdf/term-templates 库,以获取更多允许轻松匹配满足给定条件的三元组/四元组的类。
- 这种方法不仅限于过滤。也可以以类似的方式应用简单的三元组/四元组修改(只需调整“过滤生成器”
foreach
循环体)。
手动解析器/序列化器实例化
当然,可以显式实例化特定的解析器/序列化器。
这是调整解析器/序列化器配置的唯一选项,例如。
- 创建一个严格的 n-triples 解析器
$parser = new \quickRdfIo\NQuadsParser($dataFactory, true, \quickRdfIo\NQuadsParser::MODE_TRIPLES);
- 创建一个 JsonLD 序列化器,使用从给定文件读取的上下文进行压缩,并生成格式化的 JSON
$serializer = new \quickRdfIo\JsonLdSerializer( 'http://baseUri', \quickRdfIo\JsonLdSerializer::TRANSFORM_COMPACT, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT, 'context.jsonld' );
请注意,使用手动创建的解析器/序列化器实例进行解析/序列化需要更多的代码。
比较
include 'vendor/autoload.php'; $data = ...data read from somewhere... // using \quickRdfIo\Util::serialize() \quickRdfIo\Util::serialize($data, 'jsonld', 'output.jsonld'); // using manually instantiated serializer $serializer = new \quickRdfIo\JsonLdSerializer(); $output = fopen('output.jsonld', 'w'); $serializer->serialize($data, $output); fclose($output);