hardf es una biblioteca PHP 7.1+ que le permite manejar datos vinculados (RDF). Ofrece:
Tanto el analizador como el serializador tienen soporte para streaming .
Esta biblioteca es una adaptación de N3.js a PHP.
Usamos la representación triple en PHP portada desde la biblioteca NodeJS N3.js. Consulte https://github.com/rdfjs/N3.js/tree/v0.10.0#triple-representation para obtener más información
A propósito, nos centramos en el rendimiento y no en la facilidad de uso para los desarrolladores. Por lo tanto, hemos implementado esta triple representación utilizando matrices asociativas en lugar de objetos PHP. Por lo tanto, lo mismo que ocurre con N3.js, ahora es una matriz. P.ej:
<?php
$ triple = [
' subject ' => ' http://example.org/cartoons#Tom ' ,
' predicate ' => ' http://www.w3.org/1999/02/22-rdf-syntax-ns#type ' ,
' object ' => ' http://example.org/cartoons#Cat ' ,
' graph ' => ' http://example.org/mycartoon ' , #optional
];
Codifique literales de la siguiente manera (similar a N3.js)
' "Tom"@en-gb ' // lowercase language
'" 1 "^^http: //www.w3.org/2001/XMLSchema#integer' // no angular brackets <>
Instale esta biblioteca usando el compositor:
composer require pietercolpaert/ hardf
use pietercolpaert hardf TriGWriter ;
Una clase de la que se debe crear una instancia y que puede escribir TriG o Turtle
Uso de ejemplo:
$ writer = new TriGWriter ([
" prefixes " => [
" schema " => " http://schema.org/ " ,
" dct " => " http://purl.org/dc/terms/ " ,
" geo " => " http://www.w3.org/2003/01/geo/wgs84_pos# " ,
" rdf " => " http://www.w3.org/1999/02/22-rdf-syntax-ns# " ,
" rdfs " => " http://www.w3.org/2000/01/rdf-schema# "
],
" format " => " n-quads " //Other possible values: n-quads, trig or turtle
]);
$ writer -> addPrefix ( " ex " , " http://example.org/ " );
$ writer -> addTriple ( " schema:Person " , " dct:title " , "" Person " @en " , " http://example.org/#test " );
$ writer -> addTriple ( " schema:Person " , " schema:label " , "" Person " @en " , " http://example.org/#test " );
$ writer -> addTriple ( " ex:1 " , " dct:title " , "" Person1 " @en " , " http://example.org/#test " );
$ writer -> addTriple ( " ex:1 " , " http://www.w3.org/1999/02/22-rdf-syntax-ns#type " , " schema:Person " , " http://example.org/#test " );
$ writer -> addTriple ( " ex:2 " , " dct:title " , "" Person2 " @en " , " http://example.org/#test " );
$ writer -> addTriple ( " schema:Person " , " dct:title " , "" Person " @en " , " http://example.org/#test2 " );
echo $ writer -> end ();
//The method names should speak for themselves:
$ writer = new TriGWriter ([ " prefixes " : [ /* ... */ ]]);
$ writer -> addTriple ( $ subject , $ predicate , $ object , $ graphl );
$ writer -> addTriples ( $ triples );
$ writer -> addPrefix ( $ prefix , $ iri );
$ writer -> addPrefixes ( $ prefixes );
//Creates blank node($predicate and/or $object are optional)
$ writer -> blank ( $ predicate , $ object );
//Creates rdf:list with $elements
$ list = $ writer -> addList ( $ elements );
//Returns the current output it is already able to create and clear the internal memory use (useful for streaming)
$ out .= $ writer -> read ();
//Alternatively, you can listen for new chunks through a callback:
$ writer -> setReadCallback ( function ( $ output ) { echo $ output });
//Call this at the end. The return value will be the full triple output, or the rest of the output such as closing dots and brackets, unless a callback was set.
$ out .= $ writer -> end ();
//OR
$ writer -> end ();
Junto a TriG, la clase TriGParser también analiza Turtle, N-Triples, N-Quads y el envío del equipo W3C N3.
$ parser = new TriGParser ( $ options , $ tripleCallback , $ prefixCallback );
$ parser -> setTripleCallback ( $ function );
$ parser -> setPrefixCallback ( $ function );
$ parser -> parse ( $ input , $ tripleCallback , $ prefixCallback );
$ parser -> parseChunk ( $ input );
$ parser -> end ();
Usar valores de retorno y pasarlos a un escritor:
use pietercolpaert hardf TriGParser ;
use pietercolpaert hardf TriGWriter ;
$ parser = new TriGParser ([ " format " => " n-quads " ]); //also parser n-triples, n3, turtle and trig. Format is optional
$ writer = new TriGWriter ();
$ triples = $ parser -> parse ( " <A> <B> <C> <G> . " );
$ writer -> addTriples ( $ triples );
echo $ writer -> end ();
Usar devoluciones de llamada y pasarlas a un escritor:
$ parser = new TriGParser ();
$ writer = new TriGWriter ([ " format " => " trig " ]);
$ parser -> parse ( " <http://A> <https://B> <http://C> <http://G> . <A2> <https://B2> <http://C2> <http://G3> . " , function ( $ e , $ triple ) use ( $ writer ) {
if (! isset ( $ e ) && isset ( $ triple )) {
$ writer -> addTriple ( $ triple );
echo $ writer -> read (); //write out what we have so far
} else if (! isset ( $ triple )) // flags the end of the file
echo $ writer -> end (); //write the end
else
echo " Error occured: " . $ e ;
});
Cuando necesite analizar un archivo grande, necesitará analizar solo fragmentos y procesarlos ya. Puedes hacerlo de la siguiente manera:
$ writer = new TriGWriter ([ " format " => " n-quads " ]);
$ tripleCallback = function ( $ error , $ triple ) use ( $ writer ) {
if ( isset ( $ error ))
throw $ error ;
else if ( isset ( $ triple )) {
$ writer -> write ();
echo $ writer -> read ();
else if ( isset ( $ error )) {
throw $ error ;
} else {
echo $ writer -> end ();
}
};
$ prefixCallback = function ( $ prefix , $ iri ) use (& $ writer ) {
$ writer -> addPrefix ( $ prefix , $ iri );
};
$ parser = new TriGParser ([ " format " => " trig " ], $ tripleCallback , $ prefixCallback );
$ parser -> parseChunk ( $ chunk );
$ parser -> parseChunk ( $ chunk );
$ parser -> parseChunk ( $ chunk );
$ parser -> end (); //Needs to be called
format
formato de entrada (no distingue entre mayúsculas y minúsculas)turtle
- tortugatrig
- TriGtriple
, por ejemplo, triple
, ntriples
, N-Triples
- N-Triplesquad
, por ejemplo, quad
, nquads
, N-Quads
- N-Quadsn3
, por ejemplo, n3
- N3blankNodePrefix
(por defecto b0_
) prefijo forzado en nombres de nodos en blanco, por ejemplo TriGWriter(["blankNodePrefix" => 'foo'])
analizará _:bar
como _:foobar
.documentIRI
establece el URI base utilizado para resolver URI relativos (no aplicable si format
indica n-triples o n-quads)lexer
permite el uso de su propia clase Lexer. Un lexer debe proporcionar los siguientes métodos públicos:tokenize(string $input, bool $finalize = true): array<array{'subject': string, 'predicate': string, 'object': string, 'graph': string}>
tokenizeChunk(string $input): array<array{'subject': string, 'predicate': string, 'object': string, 'graph': string}>
end(): array<array{'subject': string, 'predicate': string, 'object': string, 'graph': string}>
explicitQuantifiers
- [...] Algunos documentos Turtle y N3 pueden usar sintaxis IRI relativa a la base IRI (ver aquí y aquí), por ejemplo
<> <someProperty> "some value" .
Para analizar correctamente dichos documentos se debe conocer el IRI base del documento. De lo contrario, podríamos terminar con IRI vacías (por ejemplo, para el tema del ejemplo anterior).
A veces, el IRI base está codificado en el documento, por ejemplo
@base <http://some.base/iri/> .
<> <someProperty> "some value" .
pero a veces falta. En tal caso, la especificación Turtle requiere que sigamos la sección 5.1.1 del RFC3986 que dice que si el IRI base no está encapsulado en el documento, se debe asumir que es el URI de recuperación del documento (por ejemplo, la URL en la que descargó el documento). desde o una ruta de archivo convertida a una URL). Desafortunadamente, el analizador hardf no puede adivinar esto y usted debe proporcionarlo mediante la opción de creación del analizador documentIRI
, por ejemplo.
parser = new TriGParser ([ " documentIRI " => " http://some.base/iri/ " ]);
En pocas palabras, si se encuentra con el subject/predicate/object on line X can not be parsed without knowing the the document base IRI.(...)
, inicialice el analizador con la opción documentIRI
.
use pietercolpaert hardf Util ;
Una clase estática con un par de funciones útiles para manejar nuestra triple representación específica. Le ayudará a crear y evaluar literales, IRI y prefijos expandidos.
$ bool = isIRI ( $ term );
$ bool = isLiteral ( $ term );
$ bool = isBlank ( $ term );
$ bool = isDefaultGraph ( $ term );
$ bool = inDefaultGraph ( $ triple );
$ value = getLiteralValue ( $ literal );
$ literalType = getLiteralType ( $ literal );
$ lang = getLiteralLanguage ( $ literal );
$ bool = isPrefixedName ( $ term );
$ expanded = expandPrefixedName ( $ prefixedName , $ prefixes );
$ iri = createIRI ( $ iri );
$ literalObject = createLiteral ( $ value , $ modifier = null );
Consulte la documentación en https://github.com/RubenVerborgh/N3.js#utility para obtener más información.
También ofrecemos 2 herramientas simples en bin/
como implementación de ejemplo: un validador y un traductor. Pruebe por ejemplo:
curl -H " accept: application/trig " http://fragments.dbpedia.org/2015/en | php bin/validator.php trig
curl -H " accept: application/trig " http://fragments.dbpedia.org/2015/en | php bin/convert.php trig n-triples
Comparamos el rendimiento de dos archivos tortuga y lo analizamos con la biblioteca EasyRDF en PHP, la biblioteca N3.js para NodeJS y con hardf . Estos fueron los resultados:
#triples | estructura | tiempo (ms) | memoria (MB) |
---|---|---|---|
1.866 | hardf sin opcache | 27,6 | 0,722 |
1.866 | hardf con opcache | 24,5 | 0.380 |
1.866 | EasyRDF sin opcache | 5.166,5 | 2.772 |
1.866 | EasyRDF con opcache | 5.176,2 | 2.421 |
1.866 | ARC2 con opcache | 71,9 | 1.966 |
1.866 | N3.js | 24.0 | 28.xxx |
3.896.560 | hardf sin opcache | 40.017,7 | 0,722 |
3.896.560 | hardf con opcache | 33.155,3 | 0.380 |
3.896.560 | N3.js | 7.004,0 | 59.xxx |
3.896.560 | ARC2 con opcache | 203.152,6 | 3.570,808 |
La biblioteca hardf tiene derechos de autor de Ruben Verborgh y Pieter Colpaert y está publicada bajo la licencia MIT.
Las contribuciones son bienvenidas y los informes de errores o las solicitudes de extracción siempre son útiles. Si planea implementar una característica más grande, es mejor discutir esto primero presentando un problema.