├── .Rbuildignore ├── .circleci ├── config.yml └── test.R ├── .github ├── .gitignore └── workflows │ └── R-CMD-check.yaml ├── .gitignore ├── .travis.yml ├── CONDUCT.md ├── CRAN-SUBMISSION ├── DESCRIPTION ├── LICENSE ├── NAMESPACE ├── NEWS.md ├── R ├── as_rdf.R ├── rdf.R ├── rdf_add.R ├── rdf_free.R ├── rdf_has_bdb.R ├── rdf_methods.R ├── rdf_parse.R ├── rdf_query.R ├── rdf_serialize.R ├── utilities.R └── write_nquads.R ├── README.Rmd ├── README.md ├── _pkgdown.yml ├── appveyor.yml ├── codecov.yml ├── codemeta.json ├── cran-comments.md ├── docker-compose.yml ├── docs ├── 404.html ├── CONDUCT.html ├── LICENSE-text.html ├── apple-touch-icon-120x120.png ├── apple-touch-icon-152x152.png ├── apple-touch-icon-180x180.png ├── apple-touch-icon-60x60.png ├── apple-touch-icon-76x76.png ├── apple-touch-icon.png ├── articles │ ├── articles │ │ ├── data-lake.html │ │ └── storage.html │ ├── index.html │ ├── rdf_intro.html │ └── rdf_intro_files │ │ ├── crosstalk-1.0.0 │ │ ├── css │ │ │ └── crosstalk.css │ │ └── js │ │ │ ├── crosstalk.js │ │ │ ├── crosstalk.js.map │ │ │ ├── crosstalk.min.js │ │ │ └── crosstalk.min.js.map │ │ ├── datatables-binding-0.4 │ │ └── datatables.js │ │ ├── datatables-css-0.0.0 │ │ └── datatables-crosstalk.css │ │ ├── dt-core-1.10.16 │ │ ├── css │ │ │ ├── jquery.dataTables.extra.css │ │ │ └── jquery.dataTables.min.css │ │ └── js │ │ │ └── jquery.dataTables.min.js │ │ ├── htmlwidgets-1.3 │ │ └── htmlwidgets.js │ │ └── jquery-1.12.4 │ │ ├── LICENSE.txt │ │ └── jquery.min.js ├── authors.html ├── docsearch.css ├── docsearch.js ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico ├── index.html ├── link.svg ├── logo.svg ├── news │ └── index.html ├── paper.html ├── pkgdown.css ├── pkgdown.js ├── pkgdown.yml └── reference │ ├── as_rdf.html │ ├── c.rdf.html │ ├── figures │ ├── logo.png │ └── logo.svg │ ├── index.html │ ├── rdf.html │ ├── rdf_add.html │ ├── rdf_free.html │ ├── rdf_has_bdb.html │ ├── rdf_parse.html │ ├── rdf_query.html │ ├── rdf_serialize.html │ ├── rdflib-package.html │ ├── read_nquads.html │ └── write_nquads.html ├── inst ├── CITATION ├── WORDLIST ├── docker │ ├── Dockerfile │ ├── cli │ │ └── Dockerfile │ ├── docker-compose.yml │ └── virtuoso │ │ └── Dockerfile ├── examples │ ├── deprecated.R │ ├── rdf-wo-redland.R │ ├── storage_types.R │ ├── tidy_schema.R │ └── virtuoso-direct.R ├── extdata │ ├── ex.xml │ ├── ex2.xml │ ├── github.json │ ├── person.json │ ├── person.nq │ └── vita.json └── notebook │ ├── libs │ └── remark-css │ │ ├── default-fonts.css │ │ └── default.css │ ├── profile_performance.Rmd │ └── sparql_query_examples_vita.Rmd ├── man ├── as_rdf.Rd ├── c.rdf.Rd ├── figures │ ├── logo.png │ └── logo.svg ├── rdf.Rd ├── rdf_add.Rd ├── rdf_free.Rd ├── rdf_has_bdb.Rd ├── rdf_parse.Rd ├── rdf_query.Rd ├── rdf_serialize.Rd ├── rdflib-package.Rd ├── read_nquads.Rd └── write_nquads.Rd ├── manuscripts └── rdflib │ ├── RJournal.sty │ ├── RJreferences.bib │ ├── Rlogo.png │ ├── preamble.tex │ └── rdflib.Rmd ├── paper.bib ├── paper.md ├── pkgdown └── favicon │ ├── apple-touch-icon-120x120.png │ ├── apple-touch-icon-152x152.png │ ├── apple-touch-icon-180x180.png │ ├── apple-touch-icon-60x60.png │ ├── apple-touch-icon-76x76.png │ ├── apple-touch-icon.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ └── favicon.ico ├── precompute-storage-vignette.sh ├── rdflib.Rproj ├── slides ├── img │ ├── codemeta.png │ ├── data-growth.png │ ├── data-janitor.jpg │ ├── data-lake.jpg │ ├── data-workflow.png │ ├── factory-farm.jpg │ ├── field-notes.jpg │ ├── integration.png │ ├── landsat2.jpg │ ├── neon.png │ ├── no-data-lake-scaled.jpg │ ├── no-data-lake.jpg │ ├── organic-farm.png │ ├── semantics.png │ ├── steampunk-phone.jpg │ ├── steampunk.jpg │ ├── tetris-lose.jpg │ └── tetris.jpg ├── libs │ ├── remark-css │ │ ├── default-fonts.css │ │ └── default.css │ └── remark-latest.min.js ├── slides.Rmd └── slides.html ├── tests ├── spelling.R ├── testthat.R └── testthat │ ├── test-as_rdf.R │ ├── test-parse-serialize.R │ ├── test-rdf.R │ ├── test-rdf_add.R │ ├── test-rdf_query.R │ ├── test-rdf_storage.R │ └── test-utilities.R └── vignettes ├── articles ├── data-lake.Rmd ├── data-lake.Rmd.orig ├── storage.Rmd └── storage.Rmd.orig └── rdf_intro.Rmd /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^_pkgdown\.yml$ 2 | ^CRAN-RELEASE$ 3 | ^.*\.Rproj$ 4 | ^\.Rproj\.user$ 5 | ^\.travis\.yml$ 6 | ^README\.Rmd$ 7 | ^README-.*\.png$ 8 | ^appveyor\.yml$ 9 | ^codecov\.yml$ 10 | ^codemeta\.json$ 11 | ^docs$ 12 | ^paper\.md$ 13 | ^paper\.bib$ 14 | ^CONDUCT\.md$ 15 | ^cran-comments\.md$ 16 | ^inst/notebook$ 17 | ^slides$ 18 | ^.circleci$ 19 | ^docker-compose\.yml$ 20 | ^.*\.sqlite$ 21 | ^.*\.nq$ 22 | ^.*\.gz$ 23 | pkgdown 24 | ^manuscripts/.* 25 | cache 26 | .*\.db$ 27 | ^precompute-storage-vignette\.sh$ 28 | ^CRAN-SUBMISSION$ 29 | ^\.github$ 30 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | machine: true 5 | steps: 6 | - checkout 7 | - run: docker-compose run rdflib R -f .circleci/test.R 8 | # - run: docker-compose run rdflib R -e 'x <- devtools::check(); testthat::expect_length(x$errors,0); testthat::expect_length(x$warnings,0) 9 | 10 | 11 | -------------------------------------------------------------------------------- /.circleci/test.R: -------------------------------------------------------------------------------- 1 | 2 | Sys.sleep(5) 3 | system("virtuoso-t -c /etc/virtuoso-opensource-6.1/virtuoso.ini") 4 | Sys.sleep(5) 5 | devtools::load_all() 6 | library("testthat") 7 | ## cannot catch errors with test_file() 8 | source("tests/testthat/test-rdf_storage.R") 9 | 10 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | name: R-CMD-check 10 | 11 | jobs: 12 | R-CMD-check: 13 | runs-on: ${{ matrix.config.os }} 14 | 15 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 16 | 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | config: 21 | - {os: macos-latest, r: 'release'} 22 | - {os: windows-latest, r: 'release'} 23 | # - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} 24 | # - {os: ubuntu-latest, r: 'release'} 25 | # - {os: ubuntu-latest, r: 'oldrel-1'} 26 | 27 | env: 28 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 29 | R_KEEP_PKG_SOURCE: yes 30 | 31 | steps: 32 | - uses: actions/checkout@v3 33 | 34 | - uses: r-lib/actions/setup-pandoc@v2 35 | 36 | - uses: r-lib/actions/setup-r@v2 37 | with: 38 | r-version: ${{ matrix.config.r }} 39 | http-user-agent: ${{ matrix.config.http-user-agent }} 40 | use-public-rspm: true 41 | 42 | - uses: r-lib/actions/setup-r-dependencies@v2 43 | with: 44 | extra-packages: any::rcmdcheck 45 | needs: check 46 | 47 | - uses: r-lib/actions/check-r-package@v2 48 | with: 49 | upload-snapshots: true 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | inst/doc 6 | .DS_Store 7 | *_cache 8 | *.nq 9 | *.sqlite 10 | *.tar.gz 11 | cache/ 12 | *.db 13 | 14 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # R for travis: see documentation at https://docs.travis-ci.com/user/languages/r 2 | language: R 3 | cache: packages 4 | latex: false 5 | 6 | matrix: 7 | include: 8 | - os: linux 9 | r: devel 10 | - os: linux 11 | r: release 12 | 13 | addons: 14 | apt: 15 | sources: 16 | - sourceline: 'ppa:cran/jq' 17 | packages: 18 | - librdf0-dev 19 | - libv8-dev 20 | - libjq-dev 21 | - libdb-dev 22 | after_success: 23 | - Rscript -e 'covr::codecov()' 24 | -------------------------------------------------------------------------------- /CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, we pledge to respect all people who 4 | contribute through reporting issues, posting feature requests, updating documentation, 5 | submitting pull requests or patches, and other activities. 6 | 7 | We are committed to making participation in this project a harassment-free experience for 8 | everyone, regardless of level of experience, gender, gender identity and expression, 9 | sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion. 10 | 11 | Examples of unacceptable behavior by participants include the use of sexual language or 12 | imagery, derogatory comments or personal attacks, trolling, public or private harassment, 13 | insults, or other unprofessional conduct. 14 | 15 | Project maintainers have the right and responsibility to remove, edit, or reject comments, 16 | commits, code, wiki edits, issues, and other contributions that are not aligned to this 17 | Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed 18 | from the project team. 19 | 20 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by 21 | opening an issue or contacting one or more of the project maintainers. 22 | 23 | This Code of Conduct is adapted from the Contributor Covenant 24 | (http:contributor-covenant.org), version 1.0.0, available at 25 | http://contributor-covenant.org/version/1/0/0/ 26 | -------------------------------------------------------------------------------- /CRAN-SUBMISSION: -------------------------------------------------------------------------------- 1 | Version: 0.2.8 2 | Date: 2023-12-16 17:16:07 UTC 3 | SHA: e69e961356664c68279136c94363f11385de7e60 4 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: rdflib 2 | Title: Tools to Manipulate and Query Semantic Data 3 | Version: 0.2.9 4 | Authors@R: c(person("Carl", "Boettiger", 5 | email = "cboettig@gmail.com", 6 | role = c("aut", "cre", "cph"), 7 | comment=c(ORCID = "0000-0002-1642-628X")), 8 | person("Bryce", "Mecum", 9 | role = "rev", 10 | comment=c(ORCID = "0000-0002-0381-3766")), 11 | person("Anna", "Krystalli", 12 | role = "rev", 13 | comment=c(ORCID = "0000-0002-2378-4915")), 14 | person("Viktor", "Senderov", 15 | email = "vsenderov@gmail.com", 16 | role = "ctb", 17 | comment = c(ORCID = "0000-0003-3340-5963"))) 18 | Description: The Resource Description Framework, or 'RDF' is a widely used 19 | data representation model that forms the cornerstone of the 20 | Semantic Web. 'RDF' represents data as a graph rather than 21 | the familiar data table or rectangle of relational databases. 22 | The 'rdflib' package provides a friendly and concise user interface 23 | for performing common tasks on 'RDF' data, such as reading, writing 24 | and converting between the various serializations of 'RDF' data, 25 | including 'rdfxml', 'turtle', 'nquads', 'ntriples', and 'json-ld'; 26 | creating new 'RDF' graphs, and performing graph queries using 'SPARQL'. 27 | This package wraps the low level 'redland' R package which 28 | provides direct bindings to the 'redland' C library. Additionally, 29 | the package supports the newer and more developer friendly 30 | 'JSON-LD' format through the 'jsonld' package. The package 31 | interface takes inspiration from the Python 'rdflib' library. 32 | License: MIT + file LICENSE 33 | Encoding: UTF-8 34 | URL: https://docs.ropensci.org/rdflib/, https://github.com/ropensci/rdflib 35 | BugReports: https://github.com/ropensci/rdflib/issues 36 | Imports: 37 | redland, 38 | methods, 39 | utils, 40 | stringi, 41 | readr, 42 | dplyr, 43 | tidyr 44 | RoxygenNote: 7.2.3 45 | Roxygen: list(markdown = TRUE) 46 | Suggests: 47 | magrittr, 48 | covr, 49 | testthat, 50 | knitr, 51 | rmarkdown, 52 | jqr, 53 | DT, 54 | tibble, 55 | purrr, 56 | lubridate, 57 | httr, 58 | xml2, 59 | jsonlite, 60 | repurrrsive, 61 | nycflights13, 62 | spelling, 63 | jsonld 64 | VignetteBuilder: knitr 65 | Language: en-US 66 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2019 2 | COPYRIGHT HOLDER: Carl Boettiger 3 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | S3method(as_rdf,data.frame) 4 | S3method(as_rdf,list) 5 | S3method(c,rdf) 6 | S3method(format,rdf) 7 | S3method(length,rdf) 8 | S3method(print,rdf) 9 | S3method(write_nquads,data.frame) 10 | S3method(write_nquads,rdf) 11 | export(as_rdf) 12 | export(rdf) 13 | export(rdf_add) 14 | export(rdf_free) 15 | export(rdf_has_bdb) 16 | export(rdf_parse) 17 | export(rdf_query) 18 | export(rdf_serialize) 19 | export(read_nquads) 20 | export(write_nquads) 21 | importClassesFrom(redland,Model) 22 | importClassesFrom(redland,Parser) 23 | importClassesFrom(redland,Query) 24 | importClassesFrom(redland,Serializer) 25 | importClassesFrom(redland,Statement) 26 | importClassesFrom(redland,Storage) 27 | importClassesFrom(redland,World) 28 | importFrom(dplyr,left_join) 29 | importFrom(methods,new) 30 | importFrom(readr,read_csv) 31 | importFrom(redland,is.null.externalptr) 32 | importFrom(redland,librdf_model_size) 33 | importFrom(redland,librdf_query_results_to_string2) 34 | importFrom(stringi,stri_unescape_unicode) 35 | importFrom(tidyr,gather) 36 | importFrom(utils,capture.output) 37 | importFrom(utils,download.file) 38 | importFrom(utils,write.table) 39 | importMethodsFrom(redland,addStatement) 40 | importMethodsFrom(redland,executeQuery) 41 | importMethodsFrom(redland,freeModel) 42 | importMethodsFrom(redland,freeParser) 43 | importMethodsFrom(redland,freeQuery) 44 | importMethodsFrom(redland,freeQueryResults) 45 | importMethodsFrom(redland,freeSerializer) 46 | importMethodsFrom(redland,freeStatement) 47 | importMethodsFrom(redland,freeStorage) 48 | importMethodsFrom(redland,freeWorld) 49 | importMethodsFrom(redland,parseFileIntoModel) 50 | importMethodsFrom(redland,serializeToFile) 51 | importMethodsFrom(redland,setNameSpace) 52 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # rdflib 0.2.9 2 | 3 | * Address CRAN vignette building. 4 | 5 | 6 | # rdflib 0.2.8 7 | 8 | * tests fail gracefully on CRAN without internet resources 9 | 10 | # rdflib 0.2.7 11 | 12 | make jsonld an optional dependency 13 | 14 | # rdflib 0.2.6 15 | 16 | * bugfix vroom warning 17 | 18 | # rdflib 0.2.5 19 | 20 | * bugfix UTF-8 21 | 22 | # rdflib 0.2.4 23 | 24 | * bugfix in write_nquads() for rdf method 25 | 26 | # rdflib 0.2.3 2020-01-10 27 | 28 | * Drop import of deprecated redland method, getNextResult (#33) 29 | 30 | # rdflib 0.2.2 2019-01-15 31 | 32 | * Minor patch to fix license file 33 | * Updates documentation with hex 34 | 35 | 36 | # rdflib 0.2.1 2018-11-25 37 | 38 | * Minor patch to make test compatible with breaking change in readr 1.2.0 (#30) 39 | 40 | # rdflib 0.2.0 2018-11-13 41 | 42 | ## New Features 43 | 44 | * `rdf()` supports all major storage backends: Virtuoso, SQLite, Postgres, MySQL, 45 | in addition to existing support for BDB and memory-based storage. 46 | * `length()` method added to report length of triplestore 47 | * `print()` method gains `rdf_max_print()` option and does not print huge triplestores 48 | * `print()` method sumarizes total number of triples and backend 49 | 50 | # rdflib 0.1.0 (2018-03-02) 51 | 52 | ## New Features 53 | 54 | * `rdf()` supports BDB backend for disk-based storage for large 55 | triplestores [#6](https://github.com/ropensci/rdflib/issues/6) 56 | * `rdf_parse()` gains an argument `rdf` to append triples to existing graph 57 | * adds `c()` method to concatenate `rdf` objects 58 | * Performance improvements make it possible to handle triplestores with millions of triples 59 | * Two new vignettes better introduce RDF and package functions. 60 | 61 | ## Minor Improvements 62 | 63 | * `rdf_query` now bypasses the very slow iteration over `getNextResult` 64 | approach and uses an internal redland function call to access all results 65 | at once in csv format. 66 | * experimental `as_rdf` method now uses a poor-man's nquad serializer to 67 | rapidly generate rdf (instead of slowly iterating over `add_rdf`). 68 | 69 | * `rdf_add` argument for `object` can now take all atomic types 70 | (numeric, integer, string, Date, POSIX, logical) and 71 | will automatically declare the appropriate `datatype_uri` 72 | if the user has not manually specified this. 73 | * Numerous improvements to documentation from rOpenSci onboarding feedback, see 74 | [#9](https://github.com/ropensci/rdflib/issues/9) and 75 | [#10](https://github.com/ropensci/rdflib/issues/10) 76 | * both functions and unit tests are broken out into separate files in 77 | their respective directories. 78 | * Additional example RDF data added in `extdata` 79 | * `rdf_serialize` passes `...` arguments to serializeToFile (e.g. to set a `baseUri`) 80 | 81 | ## Bug Fixes 82 | 83 | * `rdf_free()` will also remove the object from the parent frame, 84 | reducing the potential for crashing R by referring to a freed pointer. 85 | * fix encoding with UTF-8 characters (coming from nquads & ntriples) 86 | * `rdf_query()` now coerces data into appropriate type 87 | if it recognizes the data URI and can match that 88 | to an R type (a few XMLSchema types are recognized, 89 | otherwise still defaults to character string) 90 | * Memory management: All methods free memory from any 91 | temporary objects they initialize, tests free memory. 92 | (e.g. parsers, serializers, query, statement) 93 | * extend unit tests to cover new features, check UTF-8 94 | * `turtle` parser/serializer fixed 95 | 96 | ## Deprecated 97 | 98 | * `trig` support removed (not working in redland without optional 99 | libraries and alternative compile configuration) 100 | 101 | 102 | # rdflib 0.0.3 (2018-01-02) 103 | 104 | ## Bug Fixes 105 | 106 | * add paper.md 107 | * add package level documentation 108 | * set base uri when serializing json-ld to rdf ([#5](https://github.com/ropensci/rdflib/issues/5)) 109 | 110 | 111 | # rdflib 0.0.2 (2018-01-02) 112 | 113 | ## New Features 114 | 115 | * Added a `NEWS.md` file to track changes to the package. 116 | * sparql query returns a data.frame format 117 | * added a vignette 118 | * added pkgdown website for vignette 119 | 120 | # rdflib 0.0.1 (2017-12-09) 121 | 122 | * Initial prototype 123 | 124 | 125 | -------------------------------------------------------------------------------- /R/as_rdf.R: -------------------------------------------------------------------------------- 1 | 2 | #' Coerce an object into RDF 3 | #' 4 | #' Coerce an object into RDF 5 | #' @param x an object to coerce into RDF (list, list-like, or data.frame) 6 | #' @param rdf An existing rdf object, (by default a new object will be initialized) 7 | #' @param prefix A default vocabulary (URI prefix) to assume for all predicates 8 | #' @param base A base URI to assume for blank subject nodes 9 | #' @param context a named list mapping any string to a URI 10 | #' @param key_column name of a column which should be 11 | #' treated as the primary key in a table. must be unique 12 | #' @export 13 | #' 14 | #' @examples 15 | #' as_rdf(mtcars) 16 | #' as_rdf(list(repo = "rdflib", owner = list("id", "ropensci"))) 17 | as_rdf <- function(x, 18 | rdf = NULL, 19 | prefix = NULL, 20 | base = getOption("rdf_base_uri", "localhost://"), 21 | context = NULL, 22 | key_column = NULL) UseMethod("as_rdf") 23 | 24 | 25 | #' @export 26 | as_rdf.list <- function(x, 27 | rdf = NULL, 28 | prefix = NULL, 29 | base = getOption("rdf_base_uri", "localhost://"), 30 | context = NULL, 31 | key_column = NULL){ 32 | 33 | if(is.null(rdf)){ 34 | rdf <- rdf() 35 | } 36 | ## unbox length-1 lists so we can apply a context successfully 37 | if(is.list(x) && length(x) == 1) x <- x[[1]] 38 | 39 | json <- jsonlite::toJSON(x, pretty = TRUE, auto_unbox = TRUE, force = TRUE) 40 | jsonld_context <- json_context(prefix, base, context) 41 | json2 <- paste0('{\n"@context":', jsonld_context, 42 | ',\n', '"@graph": ', json, '}') 43 | rdflib::rdf_parse(json2, "jsonld", rdf = rdf) 44 | invisible(rdf) 45 | } 46 | 47 | 48 | # helper function (identical to plyr::compact) 49 | compact <- function (l) Filter(Negate(is.null), l) 50 | json_context <- function(prefix = NULL, 51 | base = getOption("rdf_base_uri", "localhost://"), 52 | context = NULL){ 53 | jsonlite::toJSON( 54 | compact(c(list("@vocab" = prefix, 55 | "@base" = base), 56 | context)), auto_unbox = TRUE) 57 | } 58 | 59 | 60 | 61 | # test2 <- tibble( 62 | # age = 5L, 63 | # name = "bob", 64 | # height = 1.9, 65 | # address = "x:address", 66 | # knows = NA 67 | # ) 68 | # as_rdf.data.frame(test2, prefix = "x:", key = "nquads") 69 | 70 | 71 | ## tidy data to rdf 72 | #' @export 73 | as_rdf.data.frame <- function(x, 74 | rdf = NULL, 75 | prefix = NULL, 76 | base = getOption("rdf_base_uri", 77 | "localhost://"), 78 | context = NULL, 79 | key_column = NULL){ 80 | 81 | if(is.null(rdf)){ 82 | rdf <- rdf() 83 | } 84 | file <- tempfile() 85 | write_nquads(x, file = file, prefix = prefix, key_column = key_column) 86 | rdf <- rdf_parse(file, rdf = rdf, format = "nquads") 87 | unlink(file) 88 | invisible(rdf) 89 | } 90 | 91 | 92 | ## Not used 93 | ## tidy data to rdf: use rownames as key column 94 | ## Note: this method is too slow to be practical on very large data frames 95 | iterative_rdf_add <- function(df, prefix = "x:", base = prefix){ 96 | rownames <- rownames(df) 97 | colnames <- colnames(df) 98 | for(i in 1:dim(df)[[1]]){ 99 | for(j in 1:dim(df)[[2]]){ 100 | rdf_add(rdf, 101 | subject = paste0(base, as.character(rownames[[i]])), 102 | predicate = paste0(prefix, colnames[[j]]), 103 | object = df$object[[i]]) 104 | } 105 | } 106 | invisible(rdf) 107 | } 108 | 109 | -------------------------------------------------------------------------------- /R/rdf.R: -------------------------------------------------------------------------------- 1 | #' Initialize an `rdf` Object 2 | #' 3 | #' @param storage Storage backend to use; see details 4 | #' @param host host address for mysql, postgres, or virtuoso storage 5 | #' @param port port for mysql (mysql storage defaults to mysql standard port, 3306) 6 | #' or postgres (postgres storage defaults to postgres standard port, 4321) 7 | #' @param user user name for postgres, mysql, or virtuoso 8 | #' @param password password for postgres, mysql, or virtuoso 9 | #' @param database name of the database to be created/used 10 | #' @param charset charset for virtuoso database, if desired 11 | #' @param dir directory of where to write sqlite or berkeley database. 12 | #' @param dsn Virtuoso dsn, either "Local Virtuoso" or "Remote Virtuoso" 13 | #' @param name name for the storage object created. Default is usually fine. 14 | #' @param new_db logical, default FALSE. Create new database or connect to existing? 15 | #' @param fallback logical, default TRUE. If requested storage system cannot initialize, 16 | #' should `rdf()` fall back on memory (default) or throw an error (fallback=FALSE)? 17 | #' @return an rdf object 18 | #' @details an rdf Object is a list of class 'rdf', consisting of 19 | #' three pointers to external C objects managed by the redland library. 20 | #' These are the `world` object: basically a top-level pointer for 21 | #' all RDF models, and a `model` object: a collection of RDF statements, 22 | #' and a `storage` object, indicating how these statements are stored. 23 | #' 24 | #' `rdflib` defaults to an in-memory hash-based storage structure. 25 | #' which should be best for most use cases. For very large triplestores, 26 | #' disk-based storage will be necessary. Enabling external storage devices 27 | #' will require additional libraries and custom compiling. See the storage 28 | #' vignette for details. 29 | #' 30 | #' @importClassesFrom redland World Model Storage 31 | #' @importMethodsFrom redland freeWorld freeModel freeStorage 32 | #' @importFrom utils capture.output 33 | #' @export 34 | #' 35 | #' @examples 36 | #' x <- rdf() 37 | #' 38 | rdf <- function(storage = c("memory", "BDB", "sqlite", 39 | "postgres", "mysql", "virtuoso"), 40 | host = NULL, 41 | port = NULL, 42 | user = NULL, 43 | password = NULL, 44 | database = NULL, 45 | charset = NULL, 46 | dir = NULL, 47 | dsn = "Local Virtuoso", 48 | name = "rdflib", 49 | new_db = FALSE, 50 | fallback = TRUE){ 51 | 52 | world <- new("World") 53 | store <- rdf_storage(storage, world, host, port, user, password, 54 | database, charset, dir, dsn, name, new_db, fallback) 55 | model <- new("Model", world = world, storage = store, options = "") 56 | structure(list(world = world, model = model, storage = store), 57 | class = "rdf") 58 | } 59 | 60 | 61 | 62 | 63 | 64 | 65 | rdf_storage <- function(storage = c("memory", 66 | "BDB", 67 | "sqlite", 68 | "postgres", 69 | "mysql", 70 | "virtuoso"), 71 | world = NULL, 72 | host = NULL, 73 | port = NULL, 74 | user = NULL, 75 | password = NULL, 76 | database = NULL, 77 | charset = NULL, 78 | dir = NULL, 79 | dsn = "Local Virtuoso", 80 | name = "rdflib", 81 | new_db = FALSE, 82 | fallback = TRUE, 83 | check_only = FALSE){ 84 | if(is.null(world)){ 85 | world <- new("World") 86 | } 87 | storage <- match.arg(storage) 88 | 89 | new <- NULL 90 | if(new_db){ 91 | new <- "yes" 92 | } 93 | if(is.null(dir)){ 94 | dir <- "." 95 | } 96 | 97 | options <- options_to_str( 98 | switch(storage, 99 | memory = list("hash-type" = "memory"), 100 | BDB = list(new = new, "hash-type" = "bdb", dir = dir), 101 | sqlite = list(new = new, dir = dir), 102 | postgres = list(new = new, host = host, port = port, 103 | database = database, user = user, password = password), 104 | mysql = list(new = new, host = host, port = port, 105 | database = database, user = user, password = password), 106 | virtuoso = list(dsn = dsn, user = user, password = password, 107 | database = database, host = host, charset = charset), 108 | list() 109 | )) 110 | 111 | store <- switch(storage, 112 | memory = new("Storage", world, "hashes", name = name, options = options), 113 | BDB = new("Storage", world, "hashes", name = name, options = options), 114 | sqlite = new("Storage", world, "sqlite", name = name, options = options), 115 | postgres = new("Storage", world, "postgresql", name = name, options = options), 116 | mysql = new("Storage", world, "mysql", name = name, options = options), 117 | virtuoso = new("Storage", world, "virtuoso", name = name, options = options) 118 | ) 119 | 120 | continue <- !is_null_pointer(store) 121 | 122 | if(check_only){ 123 | freeStorage(store) 124 | freeWorld(world) 125 | return(continue) 126 | } 127 | 128 | if(!continue){ 129 | if(fallback){ 130 | warning(paste(storage, "driver not found. Falling back on in-memory storage")) 131 | redland::freeStorage(store) 132 | store <- new("Storage", world) 133 | } else { 134 | stop(paste(storage, "not found")) 135 | } 136 | } 137 | 138 | store 139 | } 140 | 141 | 142 | compact <- function(l){ Filter(Negate(is.null), l)} 143 | options_to_str <- function(x){ 144 | x <- compact(x) 145 | n <- names(x) 146 | out <- character(0) 147 | for(i in seq_along(x)){ 148 | out <- paste0(c(out, paste0(n[[i]], "=", "'", x[[i]], "'")), collapse=",") 149 | } 150 | out 151 | } 152 | 153 | #' @importFrom redland is.null.externalptr 154 | is_null_pointer <- function(x){ 155 | redland::is.null.externalptr(x@librdf_storage@ref) 156 | # utils::capture.output(base::print.default(x@librdf_storage@ref)) == 157 | # "" 158 | } 159 | 160 | 161 | #' rdflib: Tools to Manipulate and Query Semantic Data 162 | #' 163 | #' The Resource Description Framework, or RDF is a widely used 164 | #' data representation model that forms the cornerstone of the 165 | #' Semantic Web. 'RDF' represents data as a graph rather than 166 | #' the familiar data table or rectangle of relational databases. 167 | #' 168 | #' 169 | #' It has three main goals: 170 | #' 171 | #' \itemize{ 172 | #' \item Easily read, write, and convert between all major RDF serialization formats 173 | #' \item Support SPARQL queries to extract data from an RDF graph into a data.frame 174 | #' \item Support JSON-LD format as a first-class citizen in RDF manipulations 175 | #' } 176 | #' 177 | #' For more information, see the Wikipedia pages for RDF, SPARQL, and JSON-LD: 178 | #' 179 | #' \itemize{ 180 | #' \item \url{https://en.wikipedia.org/wiki/Resource_Description_Framework} 181 | #' \item \url{https://en.wikipedia.org/wiki/SPARQL} 182 | #' \item \url{https://en.wikipedia.org/wiki/JSON-LD} 183 | #' } 184 | #' 185 | #' To learn more about rdflib, start with the vignettes: 186 | #' `browseVignettes(package = "rdflib")` 187 | #' 188 | #' Configurations via `options()` 189 | #' 190 | #' `rdf_print_format`: 191 | #' 192 | #' - NULL or "nquads" (default) 193 | #' - any valid serializer name: e.g. "rdfxml", "jsonld", "turtle", "ntriples" 194 | #' 195 | #' `rdf_base_uri`: 196 | #' 197 | #' - Default base URI to use (when serializing JSON-LD only at this time) 198 | #' default is "localhost://" 199 | #' 200 | #' `rdf_max_print`: 201 | #' 202 | #' - maximum number of lines to print from rdf, default 10 203 | #' 204 | #' 205 | "_PACKAGE" 206 | 207 | 208 | -------------------------------------------------------------------------------- /R/rdf_add.R: -------------------------------------------------------------------------------- 1 | #' Add RDF Triples 2 | #' 3 | #' add a triple (subject, predicate, object) to the RDF graph 4 | #' 5 | #' @param rdf an rdf object 6 | #' @param subject character string containing the subject 7 | #' @param predicate character string containing the predicate 8 | #' @param object character string containing the object 9 | #' @param subjectType the Node type of the subject, i.e. "uri", "blank" 10 | #' @param objectType the Node type of the object, i.e. "literal", "uri", "blank" 11 | #' @param datatype_uri the datatype URI to associate with a object literal value 12 | #' 13 | #' @return Silently returns the updated RDF graph (rdf object). 14 | #' Since the rdf object simply contains external pointers 15 | #' to the model object in C code, note that the input object is modified 16 | #' directly, so you need not assign the output of rdf_add() to anything. 17 | #' 18 | #' @details 19 | #' 20 | #' `rdf_add()` will automatically 'duck type' nodes (if looks like a duck...). 21 | #' That is, strings that look like URIs will be declared as URIs. (See 22 | #' [URI](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier)). 23 | #' Predicate should always be a URI (e.g. URL or a `prefix:string`), 24 | #' cannot be blank or literal. Subjects that look like strings will be 25 | #' treated as [Blank Nodes](https://en.wikipedia.org/wiki/Blank_node) (i.e. 26 | #' will be prefixed with `_:`). An empty subject, `""`, will create a 27 | #' blank node with random name. Objects that look like URIs will be 28 | #' typed as resource nodes, otherwise as literals. An empty object `""` 29 | #' will be treated as blank node. Set `subjectType` or `objectType` 30 | #' explicitly to override this behavior, e.g. to treat an object URI 31 | #' as a literal string. NAs are also treated as blank nodes in subject 32 | #' or object See examples for details. 33 | #' 34 | #' @references 35 | #' @importClassesFrom redland Statement 36 | #' @importMethodsFrom redland addStatement freeStatement 37 | #' @export 38 | #' 39 | #' @examples 40 | #' rdf <- rdf() 41 | #' rdf_add(rdf, 42 | #' subject="http://www.dajobe.org/", 43 | #' predicate="http://purl.org/dc/elements/1.1/language", 44 | #' object="en") 45 | #' 46 | #' ## non-URI string in subject indicates a blank subject 47 | #' ## (prefixes to "_:b0") 48 | #' rdf_add(rdf, "b0", "http://schema.org/jobTitle", "Professor") 49 | #' 50 | #' ## identically a blank subject. 51 | #' ## Note rdf is unchanged when we add the same triple twice. 52 | #' rdf_add(rdf, "b0", "http://schema.org/jobTitle", "Professor", 53 | #' subjectType = "blank") 54 | #' 55 | #' ## blank node with empty string creates a default blank node id 56 | #' rdf_add(rdf, "", "http://schema.org/jobTitle", "Professor") 57 | #' 58 | #' 59 | #' ## Subject and Object both recognized as URI resources: 60 | #' rdf_add(rdf, 61 | #' "https://orcid.org/0000-0002-1642-628X", 62 | #' "http://schema.org/homepage", 63 | #' "http://carlboettiger.info") 64 | #' 65 | #' ## Force object to be literal, not URI resource 66 | #' rdf_add(rdf, 67 | #' "https://orcid.org/0000-0002-1642-628X", 68 | #' "http://schema.org/homepage", 69 | #' "http://carlboettiger.info", 70 | #' objectType = "literal") 71 | #' 72 | #' 73 | rdf_add <- function(rdf, subject, predicate, object, 74 | subjectType = as.character(NA), 75 | objectType = as.character(NA), 76 | datatype_uri = as.character(NA)){ 77 | 78 | 79 | ## determine appropriate datatype URI in standard XSD Namespace 80 | ## based on the R object class, if no datatype has been provided. 81 | if(is.na(datatype_uri)){ 82 | datatype_uri <- xs_class(object) 83 | } 84 | 85 | ## predicate as blank node 86 | if(is.na(subject)){ 87 | subject <- "" 88 | } 89 | if(is.na(object)){ 90 | object <- "" 91 | datatype_uri <- as.character(NA) 92 | } 93 | 94 | 95 | stmt <- new("Statement", world = rdf$world, 96 | subject, predicate, as.character(object), 97 | subjectType, objectType, datatype_uri) 98 | redland::addStatement(rdf$model, stmt) 99 | 100 | redland::freeStatement(stmt) 101 | ## rdf object is a list of pointers, modified in pass-by-reference 102 | invisible(rdf) 103 | } 104 | 105 | -------------------------------------------------------------------------------- /R/rdf_free.R: -------------------------------------------------------------------------------- 1 | 2 | #' Free Memory Associated with RDF object 3 | #' 4 | #' @param rdf an rdf object 5 | #' @param rm logical, default TRUE. Remove pointer from parent.frame()? 6 | #' Usually a good idea since referring to a pointer after it has been 7 | #' removed can crash R. 8 | #' @details Free all pointers associated with an rdf object. 9 | #' Frees memory associated with the storage, world, and model 10 | #' objects. 11 | #' @export 12 | #' @examples 13 | #' rdf <- rdf() 14 | #' rdf_free(rdf) 15 | #' rm(rdf) 16 | rdf_free <- function(rdf, rm = TRUE){ 17 | redland::freeModel(rdf$model) 18 | redland::freeStorage(rdf$storage) 19 | redland::freeWorld(rdf$world) 20 | 21 | ## Remove pointer if possible 22 | ## Since referring to this pointer after it has been 23 | ## freed would otherwise just crash R. 24 | if(rm){ 25 | rm(list = deparse(substitute(rdf)), envir = parent.frame()) 26 | } 27 | } 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /R/rdf_has_bdb.R: -------------------------------------------------------------------------------- 1 | #' Check for BDB support 2 | #' 3 | #' Detect whether Berkeley Database for disk-based storage of RDF graphs 4 | #' is available. Disk-based storage requires redland package 5 | #' to be installed from source with support for the Berkeley DB 6 | #' (libdb-dev on Ubuntu, berkeley-db on homebrew), otherwise `rdf()` will 7 | #' fall back to in-memory storage with a warning. 8 | #' 9 | #' @return TRUE if BDB support is detected, false otherwise 10 | #' @export 11 | #' @examples 12 | #' rdf_has_bdb() 13 | rdf_has_bdb <- function(){ 14 | rdf_storage("BDB", new_db = TRUE, check_only = TRUE) 15 | } 16 | 17 | rdf_has_virtuoso <- function(user="dba", 18 | password="dba", 19 | dsn="Local Virtuoso"){ 20 | # has_driver <- rdf_storage("virtuoso", 21 | # user = user, 22 | # password = password, 23 | # dsn = dsn, 24 | # check_only=TRUE) 25 | r <- tryCatch(rdf("virtuoso", user = user, 26 | password = password, dsn = dsn, fallback = FALSE), 27 | error = function(e) FALSE) 28 | if(is.logical(r)){ 29 | has_connection <- r 30 | } else { 31 | rdf_add(r, "", "dc:name", "bob") 32 | if(length(r) >= 1){ 33 | has_connection <- TRUE 34 | } else { 35 | has_connection <- FALSE 36 | } 37 | rdf_free(r) 38 | } 39 | 40 | has_connection 41 | 42 | } 43 | -------------------------------------------------------------------------------- /R/rdf_methods.R: -------------------------------------------------------------------------------- 1 | 2 | #' Concatenate rdf Objects. 3 | #' 4 | #' All subsequent rdf objects will be appended to the first rdf object 5 | #' Note: this does not free memory from any of the individual rdf objects 6 | #' Note: It is generally better to avoid the use of this function by passing 7 | #' an existing rdf object to and rdf_parse or rdf_add objects. Multiple active 8 | #' rdf objects can cause problems when using disk-based storage backends. 9 | #' 10 | #' @method c rdf 11 | #' @export 12 | #' @param ... objects to be concatenated 13 | c.rdf <- function(...){ 14 | rdfs <- list(...) 15 | loc <- tempdir() 16 | rdf <- rdfs[[1]] 17 | for(i in seq_along(rdfs)){ 18 | f <- file.path(loc,paste0(i, ".rdf")) 19 | rdf_serialize(rdfs[[i]],f, format = "turtle") 20 | rdf_parse(f, rdf = rdf, format = "turtle") 21 | file.remove(f) 22 | } 23 | unlink(loc) 24 | rdf 25 | } 26 | 27 | 28 | 29 | #' @importFrom redland librdf_model_size 30 | #' @export 31 | length.rdf <- function(x){ 32 | redland::librdf_model_size(x$model@librdf_model) 33 | } 34 | 35 | #' @export 36 | print.rdf <- function(x, ...){ 37 | cat(format.rdf(x, ...), sep = "\n") 38 | } 39 | 40 | 41 | #' @importFrom stringi stri_unescape_unicode 42 | #' @export 43 | # @param max_print maximum number of lines to print of rdf preview 44 | # @param max_preview if number of triples exceeds this, no preview 45 | # will be displayed, since preview method must currently serialize 46 | # entire triplestore. 47 | format.rdf <- function(x, 48 | format = getOption("rdf_print_format", "nquads"), 49 | max_print = getOption("rdf_max_print", 10L), 50 | max_preview = 1e5, 51 | ...){ 52 | n <- redland::librdf_model_size(x$model@librdf_model) 53 | header <- paste0("Total of ", n, " triples, stored in ", x$storage@type, "\n", 54 | "-------------------------------\n") 55 | if(n < max_preview){ 56 | tmp <- tempfile() 57 | rdf_serialize(x, 58 | tmp, 59 | format = format, 60 | ...) 61 | ## Fix encoding on nquads, ntriples 62 | footer <- NULL 63 | if(n > max_print){ 64 | footer <- paste0("\n\n... with ", n-max_print, " more triples") 65 | } 66 | txt <- paste0(header, stringi::stri_unescape_unicode( 67 | paste(readLines(tmp, n = max_print), collapse = "\n")), 68 | footer) 69 | unlink(tmp) 70 | } else { 71 | txt <- paste(header, "\n (preview supressed for performance)") 72 | } 73 | txt 74 | } 75 | -------------------------------------------------------------------------------- /R/rdf_parse.R: -------------------------------------------------------------------------------- 1 | #' Parse RDF Files 2 | #' 3 | #' @param doc path, URL, or literal string of the rdf document to parse 4 | #' @param format rdf serialization format of the doc, 5 | #' one of "rdfxml", "nquads", "ntriples", "turtle" 6 | #' or "jsonld". If not provided, will try to guess based 7 | #' on file extension and fall back on rdfxml. 8 | #' @param rdf an existing rdf triplestore to extend with triples from 9 | #' the parsed file. Default will create a new rdf object. 10 | #' @param base the base URI to assume for any relative URIs (blank nodes) 11 | #' @param ... additional parameters (not implemented) 12 | #' 13 | #' @return an rdf object, containing the redland world 14 | #' and model objects 15 | #' @importClassesFrom redland World Storage Model Parser 16 | #' @importMethodsFrom redland parseFileIntoModel freeParser 17 | #' @export 18 | #' 19 | #' @examples 20 | #' doc <- system.file("extdata", "dc.rdf", package="redland") 21 | #' rdf <- rdf_parse(doc) 22 | #' 23 | rdf_parse <- function(doc, 24 | format = c("guess", 25 | "rdfxml", 26 | "nquads", 27 | "ntriples", 28 | "turtle", 29 | "jsonld"), 30 | rdf = NULL, 31 | base = getOption("rdf_base_uri", "localhost://"), 32 | ...){ 33 | 34 | format <- match.arg(format) 35 | if(format == "guess"){ 36 | format <- guess_format(doc) 37 | } 38 | 39 | ## if we get a string as input, we'll store it in tmp file here 40 | ## which we can later be sure to clean up. 41 | tmp_string <- tempfile() 42 | ## if we get json-ld, we'll need a temp location to serialize that too: 43 | tmp_json <- tempfile() 44 | 45 | # convert string input or url to local file 46 | doc <- text_or_url_to_doc(doc, tmp_string) 47 | 48 | ## redlands doesn't support jsonld. So rewrite as nquads using jsonld package 49 | ## We use tmp to avoid altering input doc, since parsing a local file should 50 | ## be a read-only task! 51 | if(format == "jsonld"){ 52 | 53 | has_jsonld <- requireNamespace("jsonld", quietly = TRUE) 54 | if (!has_jsonld) { 55 | stop("please install the jsonld package to use this functionality.") 56 | } 57 | 58 | x <- jsonld::jsonld_to_rdf(doc, 59 | options = 60 | list(base = getOption("rdf_base_uri", "localhost://"), 61 | format = "application/nquads")) 62 | writeLines(x, tmp_json) 63 | format <- "nquads" 64 | doc <- tmp_json 65 | } 66 | 67 | if(is.null(rdf)){ 68 | rdf <- rdf() 69 | } 70 | 71 | mimetype <- unname(rdf_mimetypes[format]) 72 | parser <- new("Parser", rdf$world, name = format, mimeType = mimetype) 73 | redland::parseFileIntoModel(parser, rdf$world, doc, rdf$model, baseUri = base) 74 | 75 | redland::freeParser(parser) 76 | unlink(tmp_string) 77 | unlink(tmp_json) 78 | 79 | ## return rdf object (pointer) 80 | rdf 81 | } 82 | 83 | 84 | 85 | # rdf functions like working with local files 86 | # this helper function allows us to also use URLs or strings 87 | #' @importFrom utils download.file 88 | text_or_url_to_doc <- function(x, tmp = tempfile()){ 89 | if(file.exists(x)){ 90 | return(x) 91 | } else if(grepl("^https?://", x)) { 92 | utils::download.file(x, tmp, quiet = TRUE) 93 | return(tmp) 94 | } else { 95 | writeLines(x, tmp) 96 | return(tmp) 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /R/rdf_query.R: -------------------------------------------------------------------------------- 1 | #' Perform a SPARQL Query 2 | #' 3 | #' @param rdf an rdf object (e.g. from \code{\link{rdf_parse}}) 4 | #' @param query a SPARQL query, as text string 5 | #' @param data.frame logical, should the results be returned as a data.frame? 6 | #' @param ... additional arguments to a redland initialize-Query 7 | #' 8 | #' @return a data.frame of all query results (default.) Columns will 9 | #' be named according to variable names in the SPARQL query. Returned 10 | #' object values will be coerced to match the corresponding R type 11 | #' to any associated datatype URI, if provided. If a column would 12 | #' result in mixed classes (e.g. strings and numerics), all types 13 | #' in the column will be coerced to character strings. If `data.frame` 14 | #' is false, results will be returned as a list with each element 15 | #' typed by its data URI. 16 | #' 17 | #' 18 | #' @importClassesFrom redland Query 19 | #' @importMethodsFrom redland executeQuery 20 | #' @importMethodsFrom redland freeQuery freeQueryResults 21 | #' @export 22 | #' @examples 23 | #' doc <- system.file("extdata", "dc.rdf", package="redland") 24 | #' 25 | #' sparql <- 26 | #' 'PREFIX dc: 27 | #' SELECT ?a ?c 28 | #' WHERE { ?a dc:creator ?c . }' 29 | #' 30 | #' rdf <- rdf_parse(doc) 31 | #' rdf_query(rdf, sparql) 32 | #' 33 | rdf_query <- function(rdf, query, data.frame = TRUE, ...){ 34 | queryObj <- new("Query", rdf$world, query, ...) 35 | 36 | # ... defaults are: base_uri=NULL, query_language="sparql", query_uri=NULL 37 | 38 | queryResult <- redland::executeQuery(queryObj, rdf$model) 39 | out <- getResults(queryResult) 40 | redland::freeQueryResults(queryResult) 41 | redland::freeQuery(queryObj) 42 | 43 | out 44 | } 45 | 46 | ## Notes 47 | ## readr does a pretty good job guessing types returned from sparql 48 | ## character, numeric, integer, Dates, POSIXct work fine 49 | ## logicals are denoted `true` and `false`, which readr mistakes for characters 50 | 51 | ## Redland only exports the getNextResult parser, which is extremely slow on large returns 52 | 53 | #' @importFrom readr read_csv 54 | #' @importFrom redland librdf_query_results_to_string2 55 | getResults <- function(queryResult, format = "csv", ...){ 56 | mimetype <- switch(format, 57 | "csv" = "text/csv; charset=utf-8", 58 | NULL) 59 | readr::read_csv(I(redland::librdf_query_results_to_string2( 60 | queryResult@librdf_query_results, 61 | format, mimetype, NULL, NULL)), 62 | progress = FALSE, show_col_types = FALSE, 63 | ...) 64 | } 65 | 66 | -------------------------------------------------------------------------------- /R/rdf_serialize.R: -------------------------------------------------------------------------------- 1 | #' Serialize an RDF Document 2 | #' 3 | #' @inheritParams rdf_parse 4 | #' @inheritParams rdf_query 5 | #' @param doc file path to write out to. If null, will write to character. 6 | #' @param namespace a named character containing the prefix to namespace bindings. \code{names(namespace)} are the prefixes, whereas \code{namespace} are the namespaces 7 | #' @param prefix (optional) for backward compatibility. See \code{namespace}. It contains the matching prefixes to the namespaces in \code{namespace} and is set automatically if you provide \code{namespace} as a named character vector. 8 | #' @param ... additional arguments to \code{redland::serializeToFile} 9 | #' @return rdf_serialize returns the output file path `doc` invisibly. 10 | #' This makes it easier to use rdf_serialize in pipe chains with 11 | #' \code{\link{rdf_parse}}. 12 | #' @importFrom methods new 13 | #' @importClassesFrom redland Serializer 14 | #' @importMethodsFrom redland setNameSpace serializeToFile freeSerializer 15 | #' 16 | #' @export 17 | #' @examples 18 | #' infile <- system.file("extdata", "dc.rdf", package="redland") 19 | #' out <- tempfile("file", fileext = ".rdf") 20 | #' 21 | #' some_rdf <- rdf_parse(infile) 22 | #' rdf_add(some_rdf, 23 | #' subject = "http://www.dajobe.org/dave-beckett", 24 | #' predicate = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", 25 | #' object = "http://xmlns.com/foaf/0.1/Person") 26 | #' rdf_serialize(some_rdf, out) 27 | #' 28 | #' ## With a namespace 29 | #' rdf_serialize(some_rdf, 30 | #' out, 31 | #' format = "turtle", 32 | #' namespace = c(dc = "http://purl.org/dc/elements/1.1/", 33 | #' foaf = "http://xmlns.com/foaf/0.1/") 34 | #' ) 35 | #' 36 | #' readLines(out) 37 | rdf_serialize <- function(rdf, 38 | doc = NULL, 39 | format = c("guess", 40 | "rdfxml", 41 | "nquads", 42 | "ntriples", 43 | "turtle", 44 | "jsonld"), 45 | namespace = NULL, 46 | prefix = names(namespace), 47 | base = getOption("rdf_base_uri", "localhost://"), 48 | ...){ 49 | 50 | format <- match.arg(format) 51 | if(format == "guess" & !is.null(doc)){ 52 | format <- guess_format(doc) 53 | } 54 | 55 | 56 | ## redlands doesn't support jsonld. So write as nquads and then transform 57 | jsonld_output <- format == "jsonld" 58 | if(jsonld_output){ 59 | format <- "nquads" 60 | } 61 | 62 | mimetype <- rdf_mimetypes[format] 63 | 64 | serializer <- 65 | new("Serializer", rdf$world, 66 | name = format, mimeType = mimetype) 67 | 68 | if(!is.null(namespace) && is.character(namespace) && length(namespace) >= 1 && length(namespace) == length(prefix)){ 69 | ix = 1:length(namespace) 70 | for (i in ix) { 71 | redland::setNameSpace(serializer, 72 | rdf$world, 73 | namespace = namespace[i], 74 | prefix = prefix[i]) 75 | } 76 | } 77 | 78 | if(is.null(doc)){ 79 | doc <- redland::serializeToCharacter(serializer, rdf$world, 80 | rdf$model, baseUri = base, ...) 81 | } else { 82 | status <- 83 | redland::serializeToFile(serializer, rdf$world, 84 | rdf$model, doc, baseUri = base, ...) 85 | } 86 | 87 | if(jsonld_output){ 88 | 89 | has_jsonld <- requireNamespace("jsonld", quietly = TRUE) 90 | if (!has_jsonld) { 91 | stop("please install the jsonld package to use this functionality.") 92 | } 93 | 94 | 95 | txt <- paste(readLines(doc), collapse = "\n") 96 | if(length(txt) > 0){ ## don't attempt to write empty file into json 97 | json <- jsonld::jsonld_from_rdf(txt, 98 | options = list( 99 | base = base, 100 | format = "application/nquads")) 101 | compact_json <- jsonld::jsonld_compact(json, "{}") 102 | writeLines(compact_json, doc) 103 | } 104 | } 105 | 106 | redland::freeSerializer(serializer) 107 | invisible(doc) 108 | } 109 | -------------------------------------------------------------------------------- /R/utilities.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Must match parser name & q 1.0 mimetype listed at: 4 | # http://librdf.org/raptor/api/raptor-formats-types-by-parser.html 5 | # 3 turtle options listed but only text/turtle works. 6 | # support may depend on libs avialable depending on when and how redland is compiled 7 | rdf_mimetypes <- c("nquads" = "text/x-nquads", 8 | "ntriples" = "application/n-triples", 9 | "rdfxml" = "application/rdf+xml", 10 | "trig" = "application/x-trig", 11 | "turtle" = "text/turtle") 12 | 13 | ## My redland version does not find support for these, probably optional 14 | ## additional dependency needed when compiling redland 15 | # - trig (application/x-trig) 16 | # - n3 (text/n3) 17 | # - rdfa (application/xhtml+xml, or text/html) 18 | # - rss (application/rss+xml or text/rss) 19 | 20 | 21 | 22 | guess_format <- function(doc){ 23 | switch(gsub(".*\\.(\\w+)$", "\\1", basename(doc)), 24 | "xml" = "rdfxml", 25 | "rdf" = "rdfxml", 26 | "json" = "jsonld", 27 | "nq" = "nquads", 28 | "nt" = "ntriples", 29 | "ttl" = "turtle", 30 | "jsonld" = "jsonld", 31 | "quads" = "nquads", 32 | "turtle" = "turtle", 33 | "rdfxml") 34 | } 35 | 36 | 37 | ## Don't explicitly type characters as strings, since this is default 38 | xs_class <- function(x){ 39 | 40 | type <- switch(class(x)[[1]], 41 | "numeric" = "xs:decimal", 42 | "factor" = "xs:string", 43 | "logical" = "xs:boolean", 44 | "integer" = "xs:integer", 45 | "Date" = "xs:date", 46 | "POSIXct" = "xs:dateTime", 47 | NULL 48 | ) 49 | 50 | 51 | string <- gsub("^xs:", 52 | "http://www.w3.org/2001/XMLSchema#", 53 | type) 54 | ## consistent return length, character(1) 55 | if (length(string) == 0) { 56 | string <- as.character(NA) 57 | } 58 | string 59 | } 60 | 61 | 62 | uri_prefix <- function(x){ 63 | abs_uri <- grepl("^\\w+://", x) 64 | if (abs_uri) { 65 | if (!grepl("[#/]$", x)) return(paste0(x, "#")) 66 | return(x) 67 | } 68 | if (!grepl(":$", x)) return(paste0(x, ":")) 69 | x 70 | } 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /R/write_nquads.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | #' write object out as nquads 4 | #' 5 | #' @param x an object that can be represented as nquads 6 | #' @param file output filename 7 | #' @param ... additional parameters, see examples 8 | #' 9 | #' @export 10 | #' 11 | #' @examples 12 | #' tmp <- tempfile(fileext = ".nq") 13 | #' library(datasets) 14 | #' 15 | #' ## convert data.frame to nquads 16 | #' write_nquads(iris, tmp) 17 | #' rdf <- read_nquads(tmp) 18 | #' 19 | #' ## or starting a native rdf object 20 | #' write_nquads(rdf, tempfile(fileext = ".nq")) 21 | write_nquads <- function(x, file, ...){ 22 | UseMethod("write_nquads") 23 | } 24 | 25 | 26 | #' read an nquads file 27 | #' @param file path to nquads file 28 | #' @param ... additional arguments to [rdf_parse()] 29 | #' @return an rdf object. See [rdf_parse()] 30 | #' 31 | #' @examples 32 | #' tmp <- tempfile(fileext = ".nq") 33 | #' library(datasets) 34 | #' write_nquads(iris, tmp) 35 | #' read_nquads(tmp) 36 | #' 37 | #' @export 38 | read_nquads <- function(file, ...){ 39 | rdf_parse(file, "nquads", ...) 40 | } 41 | 42 | #' @export 43 | write_nquads.rdf <- function(x, file, ...){ 44 | rdf_serialize(x, file, "nquads", ...) 45 | } 46 | 47 | #' @export 48 | write_nquads.data.frame <- function(x, 49 | file, 50 | ...){ 51 | 52 | 53 | 54 | df <- normalize_table(x, ...) 55 | poor_mans_nquads(df, file, ...) 56 | } 57 | 58 | 59 | #' @importFrom tidyr gather 60 | #' @importFrom dplyr left_join 61 | normalize_table <- function(df, key_column = NULL, ...){ 62 | ## gather looses col-classes, so pre-compute them (with base R) 63 | col_classes <- data.frame(datatype = 64 | vapply(df, 65 | xs_class, 66 | character(1))) 67 | col_classes$predicate <- rownames(col_classes) 68 | rownames(col_classes) <- NULL 69 | 70 | ## Use row names as key (subject), unless a key column is specified 71 | ## Should we verify that requested key column is indeed a unique key first? 72 | out <- df 73 | if (is.null(key_column)) { 74 | out$subject <- as.character(1:dim(out)[[1]]) 75 | } else { 76 | names(out)[names(out) == key_column] <- "subject" 77 | } 78 | 79 | ## FIXME consider taking an already-gathered table to avoid dependency? 80 | 81 | suppressWarnings(# Possible warnings about mixed types 82 | out <- tidyr::gather(out, 83 | key = "predicate", 84 | value = "object", 85 | -"subject")) 86 | 87 | ## merge is Slow! ~ 5 seconds for 800K triples 88 | ## (almost as much time as rdf_parse) 89 | # merge(out, col_classes, by = "predicate") 90 | 91 | dplyr::left_join(out, col_classes, by = "predicate") 92 | 93 | } 94 | 95 | 96 | 97 | ## x is a data.frame with columns: subject, predicate, object, & datatype 98 | #' @importFrom utils write.table 99 | poor_mans_nquads <- function(x, file, prefix = NULL, ...){ 100 | 101 | if (is.null(prefix)) { 102 | prefix <- paste0(deparse(substitute(x)), ":") 103 | warning(paste("prefix not declared, using", prefix)) 104 | } 105 | 106 | prefix <- uri_prefix(prefix) 107 | ## Currently written to be base-R compatible, 108 | ## but a tidyverse implementation may speed serialization. 109 | ## However, this seems to be fast enough that it is rarely the bottleneck 110 | 111 | ## NOTE: paste0 is a little slow ~ 1 s on 800K triples 112 | ## No datatype on blank (missing) nodes 113 | 114 | blank_object <-is.na(x$object) 115 | blank_subject <- is.na(x$subject) 116 | 117 | x$datatype[blank_object] <- as.character(NA) 118 | ## NA needs to become a unique blank node number, could do uuid or _:r 119 | x$object[blank_object] <- paste0("_:r", which(blank_object)) 120 | x$subject[blank_subject] <- paste0("_:r", which(blank_subject)) 121 | 122 | ## strings and URIs do not get a datatype 123 | needs_type <- !is.na(x$datatype) 124 | 125 | ## URIs that are not blank nodes need <> 126 | x$subject[!blank_subject] <- paste0("<", prefix, x$subject[!blank_subject], ">") 127 | ## Predicate is always a URI 128 | x$predicate <- paste0("<", prefix, x$predicate, ">") 129 | 130 | ## Strings should be quoted 131 | is_string <- !grepl("\\w+:\\w.*", x$object) & 132 | !needs_type & !blank_object 133 | x$object[is_string] <- paste0('\"', x$object[is_string] , '\"') 134 | 135 | ## URIs should be <> instead, but not blanks! 136 | x$object[!blank_object] <- gsub("(^\\w+:\\w.*$)", "<\\1>", 137 | x$object[!blank_object]) 138 | 139 | ## assumes datatype is not empty (e.g. string) 140 | x$object[needs_type] <- paste0('\"', x$object[needs_type], 141 | '\"^^<', x$datatype[needs_type], ">") 142 | 143 | ## quads needs a graph column 144 | x$graph <- "." 145 | 146 | ## write table is a little slow, ~ 1s on 800K triples, 147 | ## but readr cannot write in nquads style 148 | 149 | ## drop datatype 150 | x <- x[c("subject", "predicate", "object", "graph")] 151 | utils::write.table(x, file, col.names = FALSE, quote = FALSE, row.names = FALSE) 152 | } 153 | 154 | 155 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: github_document 3 | --- 4 | 5 | # rdflib 6 | 7 | 8 | [![R-CMD-check](https://github.com/ropensci/rdflib/workflows/R-CMD-check/badge.svg)](https://github.com/ropensci/rdflib/actions) 9 | [![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](http://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/) 10 | [![CRAN_Status_Badge](http://www.r-pkg.org/badges/version/rdflib)](https://cran.r-project.org/package=rdflib) 11 | [![](http://badges.ropensci.org/169_status.svg)](https://github.com/ropensci/software-review/issues/169) 12 | [![CRAN RStudio mirror downloads](http://cranlogs.r-pkg.org/badges/rdflib)](https://CRAN.R-project.org/package=rdflib) 13 | [![DOI](https://zenodo.org/badge/100521776.svg)](https://zenodo.org/badge/latestdoi/100521776) 14 | 15 | 16 | 17 | 18 | ```{r, echo = FALSE} 19 | knitr::opts_chunk$set( 20 | collapse = TRUE, 21 | comment = "#>", 22 | fig.path = "README-" 23 | ) 24 | ``` 25 | 26 | 27 | 28 | A friendly and consise user interface for performing common 29 | tasks on rdf data, such as parsing and converting between 30 | formats including rdfxml, turtle, nquads, ntriples, 31 | and trig, creating rdf graphs, and performing SPARQL 32 | queries. This package wraps the redland R package which 33 | provides direct bindings to the redland C library. Additionally, 34 | the package supports parsing and serialization of rdf 35 | into json-ld through the json-ld package, which binds 36 | the official json-ld javascript API. The package 37 | interface takes inspiration from the Python rdflib library. 38 | 39 | ## Installation 40 | 41 | You can install rdflib from GitHub with: 42 | 43 | ```{r gh-installation, eval = FALSE} 44 | # install.packages("devtools") 45 | devtools::install_github("ropensci/rdflib") 46 | ``` 47 | 48 | 49 | ## Basic use 50 | 51 | While not required, `rdflib` is designed to play nicely with `%>%` pipes, so we will load the `magrittr` package as well: 52 | 53 | ```{r, message=FALSE} 54 | library(magrittr) 55 | library(rdflib) 56 | ``` 57 | 58 | Parse a file and serialize into a different format: 59 | 60 | ```{r parse} 61 | system.file("extdata/dc.rdf", package="redland") %>% 62 | rdf_parse() %>% 63 | rdf_serialize("test.nquads", "nquads") 64 | ``` 65 | 66 | 67 | Perform SPARQL queries: 68 | 69 | ```{r sparql} 70 | sparql <- 71 | 'PREFIX dc: 72 | SELECT ?a ?c 73 | WHERE { ?a dc:creator ?c . }' 74 | 75 | system.file("extdata/dc.rdf", package="redland") %>% 76 | rdf_parse() %>% 77 | rdf_query(sparql) 78 | ``` 79 | 80 | Initialize graph a new object or add triples statements to an existing graph: 81 | 82 | ```{r} 83 | x <- rdf() 84 | x <- rdf_add(x, 85 | subject="http://www.dajobe.org/", 86 | predicate="http://purl.org/dc/elements/1.1/language", 87 | object="en") 88 | x 89 | ``` 90 | 91 | Change the default display format (`nquads`) for graph objects: 92 | 93 | ```{r} 94 | options(rdf_print_format = "jsonld") 95 | x 96 | ``` 97 | 98 | 99 | ## JSON-LD 100 | 101 | We can also work with the JSON-LD format through additional functions provided in the 102 | R package, `jsonld`. 103 | 104 | ```{r} 105 | out <- tempfile() 106 | rdf_serialize(x, out, "jsonld") 107 | rdf_parse(out, format = "jsonld") 108 | ``` 109 | 110 | For more information on the JSON-LD RDF API, see . 111 | 112 | ```{r include=FALSE} 113 | unlink("test.nquads") 114 | unlink(out) 115 | rdf_free(x) 116 | ``` 117 | 118 | 119 | ## Advanced Use 120 | 121 | See [articles](https://docs.ropensci.org/rdflib/articles/) from the documentation for advanced use including applications to large triplestores, example SPARQL queries, and information about additional database backends. 122 | 123 | 124 | ---- 125 | 126 | ## Citing rdflib 127 | 128 | 129 | Please also cite the underlying `redland` library when citing `rdflib` 130 | 131 | ```{r results="asis", warning=FALSE, echo=FALSE} 132 | print(citation("rdflib"), "textVersion") 133 | ``` 134 | 135 | ```{r results="asis", warning=FALSE, echo=FALSE} 136 | print(citation("redland"), "text") 137 | ``` 138 | 139 | ```{r include=FALSE} 140 | codemeta::write_codemeta() 141 | ``` 142 | 143 | 144 | [![rofooter](https://ropensci.org//public_images/github_footer.png)](https://ropensci.org/) 145 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # rdflib 3 | 4 | 5 | [![R-CMD-check](https://github.com/ropensci/rdflib/workflows/R-CMD-check/badge.svg)](https://github.com/ropensci/rdflib/actions) 6 | [![Project Status: Active – The project has reached a stable, usable 7 | state and is being actively 8 | developed.](http://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/) 9 | [![CRAN_Status_Badge](http://www.r-pkg.org/badges/version/rdflib)](https://cran.r-project.org/package=rdflib) 10 | [![](http://badges.ropensci.org/169_status.svg)](https://github.com/ropensci/software-review/issues/169) 11 | [![CRAN RStudio mirror 12 | downloads](http://cranlogs.r-pkg.org/badges/rdflib)](https://CRAN.R-project.org/package=rdflib) 13 | [![DOI](https://zenodo.org/badge/100521776.svg)](https://zenodo.org/badge/latestdoi/100521776) 14 | 15 | 16 | 17 | 18 | A friendly and consise user interface for performing common tasks on rdf 19 | data, such as parsing and converting between formats including rdfxml, 20 | turtle, nquads, ntriples, and trig, creating rdf graphs, and performing 21 | SPARQL queries. This package wraps the redland R package which provides 22 | direct bindings to the redland C library. Additionally, the package 23 | supports parsing and serialization of rdf into json-ld through the 24 | json-ld package, which binds the official json-ld javascript API. The 25 | package interface takes inspiration from the Python rdflib library. 26 | 27 | ## Installation 28 | 29 | You can install rdflib from GitHub with: 30 | 31 | ``` r 32 | # install.packages("devtools") 33 | devtools::install_github("ropensci/rdflib") 34 | ``` 35 | 36 | ## Basic use 37 | 38 | While not required, `rdflib` is designed to play nicely with `%>%` 39 | pipes, so we will load the `magrittr` package as well: 40 | 41 | ``` r 42 | library(magrittr) 43 | library(rdflib) 44 | ``` 45 | 46 | Parse a file and serialize into a different format: 47 | 48 | ``` r 49 | system.file("extdata/dc.rdf", package="redland") %>% 50 | rdf_parse() %>% 51 | rdf_serialize("test.nquads", "nquads") 52 | ``` 53 | 54 | Perform SPARQL queries: 55 | 56 | ``` r 57 | sparql <- 58 | 'PREFIX dc: 59 | SELECT ?a ?c 60 | WHERE { ?a dc:creator ?c . }' 61 | 62 | system.file("extdata/dc.rdf", package="redland") %>% 63 | rdf_parse() %>% 64 | rdf_query(sparql) 65 | #> # A tibble: 1 × 2 66 | #> a c 67 | #> 68 | #> 1 http://www.dajobe.org/ Dave Beckett 69 | ``` 70 | 71 | Initialize graph a new object or add triples statements to an existing 72 | graph: 73 | 74 | ``` r 75 | x <- rdf() 76 | x <- rdf_add(x, 77 | subject="http://www.dajobe.org/", 78 | predicate="http://purl.org/dc/elements/1.1/language", 79 | object="en") 80 | x 81 | #> Total of 1 triples, stored in hashes 82 | #> ------------------------------- 83 | #> "en" . 84 | ``` 85 | 86 | Change the default display format (`nquads`) for graph objects: 87 | 88 | ``` r 89 | options(rdf_print_format = "jsonld") 90 | x 91 | #> Total of 1 triples, stored in hashes 92 | #> ------------------------------- 93 | #> { 94 | #> "@id": "http://www.dajobe.org/", 95 | #> "http://purl.org/dc/elements/1.1/language": "en" 96 | #> } 97 | ``` 98 | 99 | ## JSON-LD 100 | 101 | We can also work with the JSON-LD format through additional functions 102 | provided in the R package, `jsonld`. 103 | 104 | ``` r 105 | out <- tempfile() 106 | rdf_serialize(x, out, "jsonld") 107 | rdf_parse(out, format = "jsonld") 108 | #> Total of 1 triples, stored in hashes 109 | #> ------------------------------- 110 | #> { 111 | #> "@id": "http://www.dajobe.org/", 112 | #> "http://purl.org/dc/elements/1.1/language": "en" 113 | #> } 114 | ``` 115 | 116 | For more information on the JSON-LD RDF API, see 117 | . 118 | 119 | ## Advanced Use 120 | 121 | See [articles](https://docs.ropensci.org/rdflib/articles/) from the 122 | documentation for advanced use including applications to large 123 | triplestores, example SPARQL queries, and information about additional 124 | database backends. 125 | 126 | ------------------------------------------------------------------------ 127 | 128 | ## Citing rdflib 129 | 130 | Please also cite the underlying `redland` library when citing `rdflib` 131 | 132 | Carl Boettiger. (2018). rdflib: A high level wrapper around the redland 133 | package for common rdf applications (Version 0.1.0). Zenodo. 134 | 135 | 136 | Jones M, Slaughter P, Ooms J, Boettiger C, Chamberlain S (2022). 137 | *redland: RDF Library Bindings in R*. 138 | , R package version 1.0.17-16, 139 | . 140 | 141 | [![rofooter](https://ropensci.org//public_images/github_footer.png)](https://ropensci.org/) 142 | -------------------------------------------------------------------------------- /_pkgdown.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/_pkgdown.yml -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # DO NOT CHANGE the "init" and "install" sections below 2 | environment: 3 | global: 4 | USE_RTOOLS: true 5 | 6 | # Download script file from GitHub 7 | init: 8 | ps: | 9 | $ErrorActionPreference = "Stop" 10 | Invoke-WebRequest http://raw.github.com/krlmlr/r-appveyor/master/scripts/appveyor-tool.ps1 -OutFile "..\appveyor-tool.ps1" 11 | Import-Module '..\appveyor-tool.ps1' 12 | 13 | install: 14 | ps: Bootstrap 15 | 16 | cache: 17 | - C:\RLibrary 18 | 19 | # Adapt as necessary starting from here 20 | 21 | build_script: 22 | - travis-tool.sh install_deps 23 | 24 | test_script: 25 | - travis-tool.sh run_tests 26 | 27 | on_failure: 28 | - 7z a failure.zip *.Rcheck\* 29 | - appveyor PushArtifact failure.zip 30 | 31 | artifacts: 32 | - path: '*.Rcheck\**\*.log' 33 | name: Logs 34 | 35 | - path: '*.Rcheck\**\*.out' 36 | name: Logs 37 | 38 | - path: '*.Rcheck\**\*.fail' 39 | name: Logs 40 | 41 | - path: '*.Rcheck\**\*.Rout' 42 | name: Logs 43 | 44 | - path: '\*_*.tar.gz' 45 | name: Bits 46 | 47 | - path: '\*_*.zip' 48 | name: Bits 49 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | Dear CRAN maintainers, 2 | 3 | This release provides a minor update as described in the package NEWS.md 4 | 5 | 6 | ## R CMD check results 7 | 8 | 0 errors | 0 warnings | 0 notes 9 | 10 | 11 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | 4 | mariadb: 5 | image: mariadb 6 | environment: 7 | - MYSQL_ROOT_PASSWORD=rdflib 8 | 9 | postgres: 10 | image: postgres 11 | environment: 12 | - POSTGRES_PASSWORD=rdflib 13 | 14 | rdflib: 15 | image: ropensci/rdflib 16 | volumes: 17 | - .:/data 18 | - virtuoso_volume:/var/lib/virtuoso-opensource-6.1/db 19 | working_dir: /data 20 | depends_on: 21 | - postgres 22 | - mariadb 23 | 24 | volumes: 25 | virtuoso_volume: 26 | 27 | 28 | -------------------------------------------------------------------------------- /docs/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Page not found (404) • rdflib 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 60 | 61 | 62 | 63 | 64 | 65 | 66 |
67 |
68 | 128 | 129 | 130 | 131 |
132 | 133 |
134 |
135 | 138 | 139 | Content not found. Please use links in the navbar. 140 | 141 |
142 | 143 |
144 | 145 | 146 | 147 |
148 | 151 | 152 |
153 |

Site built with pkgdown 1.4.1.

154 |
155 | 156 |
157 |
158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /docs/CONDUCT.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Contributor Code of Conduct • rdflib 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 60 | 61 | 62 | 63 | 64 | 65 | 66 |
67 |
68 | 128 | 129 | 130 | 131 |
132 | 133 |
134 |
135 | 138 | 139 |
140 | 141 |

As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.

142 |

We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.

143 |

Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.

144 |

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.

145 |

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.

146 |

This Code of Conduct is adapted from the Contributor Covenant (http:contributor-covenant.org), version 1.0.0, available at http://contributor-covenant.org/version/1/0/0/

147 |
148 | 149 |
150 | 151 |
152 | 153 | 154 | 155 |
156 | 159 | 160 |
161 |

Site built with pkgdown 1.4.1.

162 |
163 | 164 |
165 |
166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /docs/LICENSE-text.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | License • rdflib 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 60 | 61 | 62 | 63 | 64 | 65 | 66 |
67 |
68 | 128 | 129 | 130 | 131 |
132 | 133 |
134 |
135 | 138 | 139 |
YEAR: 2019
140 | COPYRIGHT HOLDER: Carl Boettiger
141 | 
142 | 143 |
144 | 145 |
146 | 147 | 148 | 149 |
150 | 153 | 154 |
155 |

Site built with pkgdown 1.4.1.

156 |
157 | 158 |
159 |
160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /docs/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/docs/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /docs/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/docs/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /docs/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/docs/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /docs/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/docs/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /docs/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/docs/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /docs/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/docs/apple-touch-icon.png -------------------------------------------------------------------------------- /docs/articles/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Articles • rdflib 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 60 | 61 | 62 | 63 | 64 | 65 | 66 |
67 |
68 | 128 | 129 | 130 | 131 |
132 | 133 |
134 |
135 | 138 | 139 | 149 |
150 |
151 | 152 | 153 |
154 | 157 | 158 |
159 |

Site built with pkgdown 1.4.1.

160 |
161 | 162 |
163 |
164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /docs/articles/rdf_intro_files/crosstalk-1.0.0/css/crosstalk.css: -------------------------------------------------------------------------------- 1 | /* Adjust margins outwards, so column contents line up with the edges of the 2 | parent of container-fluid. */ 3 | .container-fluid.crosstalk-bscols { 4 | margin-left: -30px; 5 | margin-right: -30px; 6 | white-space: normal; 7 | } 8 | 9 | /* But don't adjust the margins outwards if we're directly under the body, 10 | i.e. we were the top-level of something at the console. */ 11 | body > .container-fluid.crosstalk-bscols { 12 | margin-left: auto; 13 | margin-right: auto; 14 | } 15 | 16 | .crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column { 17 | display: inline-block; 18 | padding-right: 12px; 19 | vertical-align: top; 20 | } 21 | 22 | @media only screen and (max-width:480px) { 23 | .crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column { 24 | display: block; 25 | padding-right: inherit; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /docs/articles/rdf_intro_files/datatables-css-0.0.0/datatables-crosstalk.css: -------------------------------------------------------------------------------- 1 | .dt-crosstalk-fade { 2 | opacity: 0.2; 3 | } 4 | 5 | html body div.DTS div.dataTables_scrollBody { 6 | background: none; 7 | } 8 | -------------------------------------------------------------------------------- /docs/articles/rdf_intro_files/dt-core-1.10.16/css/jquery.dataTables.extra.css: -------------------------------------------------------------------------------- 1 | /* Selected rows/cells */ 2 | table.dataTable tr.selected td, table.dataTable td.selected { 3 | background-color: #b0bed9 !important; 4 | } 5 | /* In case of scrollX/Y or FixedHeader */ 6 | .dataTables_scrollBody .dataTables_sizing { 7 | visibility: hidden; 8 | } 9 | -------------------------------------------------------------------------------- /docs/articles/rdf_intro_files/jquery-1.12.4/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2005, 2014 jQuery Foundation and other contributors, 2 | https://jquery.org/ 3 | 4 | This software consists of voluntary contributions made by many 5 | individuals. For exact contribution history, see the revision history 6 | available at https://github.com/jquery/jquery 7 | 8 | The following license applies to all parts of this software except as 9 | documented below: 10 | 11 | ==== 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining 14 | a copy of this software and associated documentation files (the 15 | "Software"), to deal in the Software without restriction, including 16 | without limitation the rights to use, copy, modify, merge, publish, 17 | distribute, sublicense, and/or sell copies of the Software, and to 18 | permit persons to whom the Software is furnished to do so, subject to 19 | the following conditions: 20 | 21 | The above copyright notice and this permission notice shall be 22 | included in all copies or substantial portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 28 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 29 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 30 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 31 | 32 | ==== 33 | 34 | All files located in the node_modules and external directories are 35 | externally maintained libraries used by this software which have their 36 | own licenses; we recommend you read them, as their terms may differ from 37 | the terms above. 38 | -------------------------------------------------------------------------------- /docs/docsearch.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | 3 | // register a handler to move the focus to the search bar 4 | // upon pressing shift + "/" (i.e. "?") 5 | $(document).on('keydown', function(e) { 6 | if (e.shiftKey && e.keyCode == 191) { 7 | e.preventDefault(); 8 | $("#search-input").focus(); 9 | } 10 | }); 11 | 12 | $(document).ready(function() { 13 | // do keyword highlighting 14 | /* modified from https://jsfiddle.net/julmot/bL6bb5oo/ */ 15 | var mark = function() { 16 | 17 | var referrer = document.URL ; 18 | var paramKey = "q" ; 19 | 20 | if (referrer.indexOf("?") !== -1) { 21 | var qs = referrer.substr(referrer.indexOf('?') + 1); 22 | var qs_noanchor = qs.split('#')[0]; 23 | var qsa = qs_noanchor.split('&'); 24 | var keyword = ""; 25 | 26 | for (var i = 0; i < qsa.length; i++) { 27 | var currentParam = qsa[i].split('='); 28 | 29 | if (currentParam.length !== 2) { 30 | continue; 31 | } 32 | 33 | if (currentParam[0] == paramKey) { 34 | keyword = decodeURIComponent(currentParam[1].replace(/\+/g, "%20")); 35 | } 36 | } 37 | 38 | if (keyword !== "") { 39 | $(".contents").unmark({ 40 | done: function() { 41 | $(".contents").mark(keyword); 42 | } 43 | }); 44 | } 45 | } 46 | }; 47 | 48 | mark(); 49 | }); 50 | }); 51 | 52 | /* Search term highlighting ------------------------------*/ 53 | 54 | function matchedWords(hit) { 55 | var words = []; 56 | 57 | var hierarchy = hit._highlightResult.hierarchy; 58 | // loop to fetch from lvl0, lvl1, etc. 59 | for (var idx in hierarchy) { 60 | words = words.concat(hierarchy[idx].matchedWords); 61 | } 62 | 63 | var content = hit._highlightResult.content; 64 | if (content) { 65 | words = words.concat(content.matchedWords); 66 | } 67 | 68 | // return unique words 69 | var words_uniq = [...new Set(words)]; 70 | return words_uniq; 71 | } 72 | 73 | function updateHitURL(hit) { 74 | 75 | var words = matchedWords(hit); 76 | var url = ""; 77 | 78 | if (hit.anchor) { 79 | url = hit.url_without_anchor + '?q=' + escape(words.join(" ")) + '#' + hit.anchor; 80 | } else { 81 | url = hit.url + '?q=' + escape(words.join(" ")); 82 | } 83 | 84 | return url; 85 | } 86 | -------------------------------------------------------------------------------- /docs/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/docs/favicon-16x16.png -------------------------------------------------------------------------------- /docs/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/docs/favicon-32x32.png -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/docs/favicon.ico -------------------------------------------------------------------------------- /docs/link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /docs/paper.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Summary • rdflib 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 60 | 61 | 62 | 63 | 64 | 65 | 66 |
67 |
68 | 128 | 129 | 130 | 131 |
132 | 133 |
134 |
135 | 138 | 139 | 140 |
141 |

title: ‘Tools to Manipulate and Query Semantic Data’ tags:

142 |
    143 |
  • linked data
  • 144 |
  • rdf
  • 145 |
  • sparql
  • 146 |
  • semantic
  • 147 |
  • json-ld authors:
  • 148 |
  • name: Carl Boettiger orcid: 0000-0002-1642-628X affiliation: 1 affiliations:
  • 149 |
  • name: University of California, Berkeley index: 1 date: 2017-12-11 bibliography: paper.bib —
  • 150 |
151 |
152 | 153 |

The Resource Description Framework, or RDF [@RDF; @W3C_RDF] is a widely used data representation model that forms the cornerstone of the Semantic Web. RDF represents data as a graph rather than the familiar data table or rectangle of relational databases. The rdflib package provides a friendly and concise user interface for performing common tasks on RDF data, such as reading, writing and converting between the various serializations of RDF data, including rdfxml, turtle, nquads, ntriples, and json-ld; creating new rdf graphs, and performing graph queries using SPARQL [@SPARQL; @W3C_SPARQL]. This package wraps the low level redland R package [@redland] which provides direct bindings to the redland C library. Additionally, the package supports the newer and more developer friendly JSON-LD format through the jsonld package [@jsonld; @W3C_jsonld].

154 |
155 |
156 |

157 | References

158 |
159 | 160 | 161 |
162 | 163 |
164 | 165 | 166 | 167 |
168 | 171 | 172 |
173 |

Site built with pkgdown 1.4.1.

174 |
175 | 176 |
177 |
178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /docs/pkgdown.css: -------------------------------------------------------------------------------- 1 | /* Sticky footer */ 2 | 3 | /** 4 | * Basic idea: https://philipwalton.github.io/solved-by-flexbox/demos/sticky-footer/ 5 | * Details: https://github.com/philipwalton/solved-by-flexbox/blob/master/assets/css/components/site.css 6 | * 7 | * .Site -> body > .container 8 | * .Site-content -> body > .container .row 9 | * .footer -> footer 10 | * 11 | * Key idea seems to be to ensure that .container and __all its parents__ 12 | * have height set to 100% 13 | * 14 | */ 15 | 16 | html, body { 17 | height: 100%; 18 | } 19 | 20 | body > .container { 21 | display: flex; 22 | height: 100%; 23 | flex-direction: column; 24 | } 25 | 26 | body > .container .row { 27 | flex: 1 0 auto; 28 | } 29 | 30 | footer { 31 | margin-top: 45px; 32 | padding: 35px 0 36px; 33 | border-top: 1px solid #e5e5e5; 34 | color: #666; 35 | display: flex; 36 | flex-shrink: 0; 37 | } 38 | footer p { 39 | margin-bottom: 0; 40 | } 41 | footer div { 42 | flex: 1; 43 | } 44 | footer .pkgdown { 45 | text-align: right; 46 | } 47 | footer p { 48 | margin-bottom: 0; 49 | } 50 | 51 | img.icon { 52 | float: right; 53 | } 54 | 55 | img { 56 | max-width: 100%; 57 | } 58 | 59 | /* Fix bug in bootstrap (only seen in firefox) */ 60 | summary { 61 | display: list-item; 62 | } 63 | 64 | /* Typographic tweaking ---------------------------------*/ 65 | 66 | .contents .page-header { 67 | margin-top: calc(-60px + 1em); 68 | } 69 | 70 | /* Section anchors ---------------------------------*/ 71 | 72 | a.anchor { 73 | margin-left: -30px; 74 | display:inline-block; 75 | width: 30px; 76 | height: 30px; 77 | visibility: hidden; 78 | 79 | background-image: url(./link.svg); 80 | background-repeat: no-repeat; 81 | background-size: 20px 20px; 82 | background-position: center center; 83 | } 84 | 85 | .hasAnchor:hover a.anchor { 86 | visibility: visible; 87 | } 88 | 89 | @media (max-width: 767px) { 90 | .hasAnchor:hover a.anchor { 91 | visibility: hidden; 92 | } 93 | } 94 | 95 | 96 | /* Fixes for fixed navbar --------------------------*/ 97 | 98 | .contents h1, .contents h2, .contents h3, .contents h4 { 99 | padding-top: 60px; 100 | margin-top: -40px; 101 | } 102 | 103 | /* Sidebar --------------------------*/ 104 | 105 | #sidebar { 106 | margin-top: 30px; 107 | position: -webkit-sticky; 108 | position: sticky; 109 | top: 70px; 110 | } 111 | #sidebar h2 { 112 | font-size: 1.5em; 113 | margin-top: 1em; 114 | } 115 | 116 | #sidebar h2:first-child { 117 | margin-top: 0; 118 | } 119 | 120 | #sidebar .list-unstyled li { 121 | margin-bottom: 0.5em; 122 | } 123 | 124 | .orcid { 125 | height: 16px; 126 | /* margins are required by official ORCID trademark and display guidelines */ 127 | margin-left:4px; 128 | margin-right:4px; 129 | vertical-align: middle; 130 | } 131 | 132 | /* Reference index & topics ----------------------------------------------- */ 133 | 134 | .ref-index th {font-weight: normal;} 135 | 136 | .ref-index td {vertical-align: top;} 137 | .ref-index .icon {width: 40px;} 138 | .ref-index .alias {width: 40%;} 139 | .ref-index-icons .alias {width: calc(40% - 40px);} 140 | .ref-index .title {width: 60%;} 141 | 142 | .ref-arguments th {text-align: right; padding-right: 10px;} 143 | .ref-arguments th, .ref-arguments td {vertical-align: top;} 144 | .ref-arguments .name {width: 20%;} 145 | .ref-arguments .desc {width: 80%;} 146 | 147 | /* Nice scrolling for wide elements --------------------------------------- */ 148 | 149 | table { 150 | display: block; 151 | overflow: auto; 152 | } 153 | 154 | /* Syntax highlighting ---------------------------------------------------- */ 155 | 156 | pre { 157 | word-wrap: normal; 158 | word-break: normal; 159 | border: 1px solid #eee; 160 | } 161 | 162 | pre, code { 163 | background-color: #f8f8f8; 164 | color: #333; 165 | } 166 | 167 | pre code { 168 | overflow: auto; 169 | word-wrap: normal; 170 | white-space: pre; 171 | } 172 | 173 | pre .img { 174 | margin: 5px 0; 175 | } 176 | 177 | pre .img img { 178 | background-color: #fff; 179 | display: block; 180 | height: auto; 181 | } 182 | 183 | code a, pre a { 184 | color: #375f84; 185 | } 186 | 187 | a.sourceLine:hover { 188 | text-decoration: none; 189 | } 190 | 191 | .fl {color: #1514b5;} 192 | .fu {color: #000000;} /* function */ 193 | .ch,.st {color: #036a07;} /* string */ 194 | .kw {color: #264D66;} /* keyword */ 195 | .co {color: #888888;} /* comment */ 196 | 197 | .message { color: black; font-weight: bolder;} 198 | .error { color: orange; font-weight: bolder;} 199 | .warning { color: #6A0366; font-weight: bolder;} 200 | 201 | /* Clipboard --------------------------*/ 202 | 203 | .hasCopyButton { 204 | position: relative; 205 | } 206 | 207 | .btn-copy-ex { 208 | position: absolute; 209 | right: 0; 210 | top: 0; 211 | visibility: hidden; 212 | } 213 | 214 | .hasCopyButton:hover button.btn-copy-ex { 215 | visibility: visible; 216 | } 217 | 218 | /* headroom.js ------------------------ */ 219 | 220 | .headroom { 221 | will-change: transform; 222 | transition: transform 200ms linear; 223 | } 224 | .headroom--pinned { 225 | transform: translateY(0%); 226 | } 227 | .headroom--unpinned { 228 | transform: translateY(-100%); 229 | } 230 | 231 | /* mark.js ----------------------------*/ 232 | 233 | mark { 234 | background-color: rgba(255, 255, 51, 0.5); 235 | border-bottom: 2px solid rgba(255, 153, 51, 0.3); 236 | padding: 1px; 237 | } 238 | 239 | /* vertical spacing after htmlwidgets */ 240 | .html-widget { 241 | margin-bottom: 10px; 242 | } 243 | 244 | /* fontawesome ------------------------ */ 245 | 246 | .fab { 247 | font-family: "Font Awesome 5 Brands" !important; 248 | } 249 | 250 | /* don't display links in code chunks when printing */ 251 | /* source: https://stackoverflow.com/a/10781533 */ 252 | @media print { 253 | code a:link:after, code a:visited:after { 254 | content: ""; 255 | } 256 | } 257 | -------------------------------------------------------------------------------- /docs/pkgdown.js: -------------------------------------------------------------------------------- 1 | /* http://gregfranko.com/blog/jquery-best-practices/ */ 2 | (function($) { 3 | $(function() { 4 | 5 | $('.navbar-fixed-top').headroom(); 6 | 7 | $('body').css('padding-top', $('.navbar').height() + 10); 8 | $(window).resize(function(){ 9 | $('body').css('padding-top', $('.navbar').height() + 10); 10 | }); 11 | 12 | $('body').scrollspy({ 13 | target: '#sidebar', 14 | offset: 60 15 | }); 16 | 17 | $('[data-toggle="tooltip"]').tooltip(); 18 | 19 | var cur_path = paths(location.pathname); 20 | var links = $("#navbar ul li a"); 21 | var max_length = -1; 22 | var pos = -1; 23 | for (var i = 0; i < links.length; i++) { 24 | if (links[i].getAttribute("href") === "#") 25 | continue; 26 | // Ignore external links 27 | if (links[i].host !== location.host) 28 | continue; 29 | 30 | var nav_path = paths(links[i].pathname); 31 | 32 | var length = prefix_length(nav_path, cur_path); 33 | if (length > max_length) { 34 | max_length = length; 35 | pos = i; 36 | } 37 | } 38 | 39 | // Add class to parent
  • , and enclosing
  • if in dropdown 40 | if (pos >= 0) { 41 | var menu_anchor = $(links[pos]); 42 | menu_anchor.parent().addClass("active"); 43 | menu_anchor.closest("li.dropdown").addClass("active"); 44 | } 45 | }); 46 | 47 | function paths(pathname) { 48 | var pieces = pathname.split("/"); 49 | pieces.shift(); // always starts with / 50 | 51 | var end = pieces[pieces.length - 1]; 52 | if (end === "index.html" || end === "") 53 | pieces.pop(); 54 | return(pieces); 55 | } 56 | 57 | // Returns -1 if not found 58 | function prefix_length(needle, haystack) { 59 | if (needle.length > haystack.length) 60 | return(-1); 61 | 62 | // Special case for length-0 haystack, since for loop won't run 63 | if (haystack.length === 0) { 64 | return(needle.length === 0 ? 0 : -1); 65 | } 66 | 67 | for (var i = 0; i < haystack.length; i++) { 68 | if (needle[i] != haystack[i]) 69 | return(i); 70 | } 71 | 72 | return(haystack.length); 73 | } 74 | 75 | /* Clipboard --------------------------*/ 76 | 77 | function changeTooltipMessage(element, msg) { 78 | var tooltipOriginalTitle=element.getAttribute('data-original-title'); 79 | element.setAttribute('data-original-title', msg); 80 | $(element).tooltip('show'); 81 | element.setAttribute('data-original-title', tooltipOriginalTitle); 82 | } 83 | 84 | if(ClipboardJS.isSupported()) { 85 | $(document).ready(function() { 86 | var copyButton = ""; 87 | 88 | $(".examples, div.sourceCode").addClass("hasCopyButton"); 89 | 90 | // Insert copy buttons: 91 | $(copyButton).prependTo(".hasCopyButton"); 92 | 93 | // Initialize tooltips: 94 | $('.btn-copy-ex').tooltip({container: 'body'}); 95 | 96 | // Initialize clipboard: 97 | var clipboardBtnCopies = new ClipboardJS('[data-clipboard-copy]', { 98 | text: function(trigger) { 99 | return trigger.parentNode.textContent; 100 | } 101 | }); 102 | 103 | clipboardBtnCopies.on('success', function(e) { 104 | changeTooltipMessage(e.trigger, 'Copied!'); 105 | e.clearSelection(); 106 | }); 107 | 108 | clipboardBtnCopies.on('error', function() { 109 | changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy'); 110 | }); 111 | }); 112 | } 113 | })(window.jQuery || window.$) 114 | -------------------------------------------------------------------------------- /docs/pkgdown.yml: -------------------------------------------------------------------------------- 1 | pandoc: 2.3.1 2 | pkgdown: 1.4.1 3 | pkgdown_sha: ~ 4 | articles: 5 | data-lake: articles/data-lake.html 6 | storage: articles/storage.html 7 | rdf_intro: rdf_intro.html 8 | 9 | -------------------------------------------------------------------------------- /docs/reference/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/docs/reference/figures/logo.png -------------------------------------------------------------------------------- /docs/reference/rdf_has_bdb.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Check for BDB support — rdf_has_bdb • rdflib 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 65 | 66 | 67 | 68 | 69 | 70 | 71 |
    72 |
    73 | 133 | 134 | 135 | 136 |
    137 | 138 |
    139 |
    140 | 145 | 146 |
    147 |

    Detect whether Berkeley Database for disk-based storage of RDF graphs 148 | is available. Disk-based storage requires redland package 149 | to be installed from source with support for the Berkeley DB 150 | (libdb-dev on Ubuntu, berkeley-db on homebrew), otherwise rdf() will 151 | fall back to in-memory storage with a warning.

    152 |
    153 | 154 |
    rdf_has_bdb()
    155 | 156 | 157 |

    Value

    158 | 159 |

    TRUE if BDB support is detected, false otherwise

    160 | 161 |

    Examples

    162 |
    rdf_has_bdb()
    #> [1] FALSE
    163 |
    164 | 172 |
    173 | 174 | 175 |
    176 | 179 | 180 |
    181 |

    Site built with pkgdown 1.4.1.

    182 |
    183 | 184 |
    185 |
    186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /inst/CITATION: -------------------------------------------------------------------------------- 1 | 2 | bibentry( 3 | bibtype = 'manual', 4 | title = 'rdflib: A high level wrapper around the redland package for common rdf applications', 5 | author = person("Carl", "Boettiger", email = "cboettig@gmail.com"), 6 | role = c("aut", "cre", "cph"), 7 | comment=c(ORCID = "0000-0002-1642-628X"), 8 | year = '2018', 9 | publisher = 'Zenodo', 10 | doi = '10.5281/zenodo.1098478', 11 | url = 'https://doi.org/10.5281/zenodo.1098478', 12 | textVersion = 'Carl Boettiger. (2018). rdflib: A high level wrapper around the redland package for common rdf applications (Version 0.1.0). Zenodo. ' 13 | ) -------------------------------------------------------------------------------- /inst/WORDLIST: -------------------------------------------------------------------------------- 1 | BDB 2 | CMD 3 | CircleCI 4 | DOI 5 | DataTypes 6 | Dockerfile 7 | Grolemund 8 | JSON 9 | LD 10 | NCName 11 | Norvig 12 | ORCID 13 | OSX 14 | Ooms 15 | POSTGRES 16 | Postgres 17 | RDF 18 | RDFa 19 | README 20 | RStudio 21 | SPARQL 22 | Schemas 23 | URI 24 | URIs 25 | URNs 26 | UUIDs 27 | Wickham 28 | XMLSchema 29 | Zenodo 30 | analgous 31 | berkeley 32 | bugfix 33 | charset 34 | consise 35 | csv 36 | datatypes 37 | dev 38 | dsn 39 | getNextResult 40 | homebrew 41 | ifying 42 | javascript 43 | json 44 | jsonld 45 | ld 46 | libdb 47 | lossy 48 | md 49 | mysql 50 | nquad 51 | nquads 52 | ntriples 53 | onboarding 54 | parsers 55 | pkgdown 56 | postgres 57 | pre 58 | prebuild 59 | rOpenSci 60 | rdf 61 | rdfxml 62 | readr 63 | rectangling 64 | redland 65 | rofooter 66 | serializeToFile 67 | serializer 68 | serializers 69 | sparql 70 | sqlite 71 | sumarizes 72 | tidyverse 73 | toolset 74 | triplestore 75 | triplestores 76 | ubiquitious 77 | un 78 | uri 79 | vroom 80 | yml 81 | -------------------------------------------------------------------------------- /inst/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rocker/tidyverse:latest 2 | 3 | ## consider removing build deps 4 | RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq install \ 5 | libxml2-dev \ 6 | libcurl4-openssl-dev \ 7 | libssl-dev \ 8 | git \ 9 | automake \ 10 | libtool \ 11 | gtk-doc-tools \ 12 | bison \ 13 | flex \ 14 | libgmp-dev \ 15 | libmhash-dev \ 16 | libgcrypt20-dev \ 17 | libpcre3-dev \ 18 | libv8-dev \ 19 | libjq-dev \ 20 | libpq-dev \ 21 | libdb-dev \ 22 | libsqlite3-dev \ 23 | libmariadbclient-dev \ 24 | librdf-storage-virtuoso \ 25 | virtuoso-server \ 26 | unixodbc-dev 27 | 28 | RUN git clone git://github.com/dajobe/raptor.git && \ 29 | cd raptor && \ 30 | ./autogen.sh && \ 31 | make && \ 32 | make install && \ 33 | cd .. && \ 34 | git clone git://github.com/dajobe/rasqal.git && \ 35 | cd rasqal && \ 36 | ./autogen.sh && \ 37 | make && \ 38 | make install && \ 39 | cd .. && \ 40 | git clone git://github.com/dajobe/librdf.git && \ 41 | cd librdf && \ 42 | ./autogen.sh && \ 43 | make && \ 44 | make install 45 | 46 | RUN R -e "install.packages('remotes')" && \ 47 | R -e "remotes::install_github('ropensci/redland-bindings/R/redland')" && \ 48 | R -e "remotes::install_github('ropensci/rdflib', dep=TRUE)" 49 | 50 | RUN echo '[Local Virtuoso]\ 51 | \nDriver=/usr/lib/x86_64-linux-gnu/odbc/virtodbc_r.so\ 52 | \nAddress=localhost:1111' >> /etc/odbc.ini 53 | 54 | RUN mkdir -p /etc/services.d/virtuoso \ 55 | && echo '#!/usr/bin/with-contenv bash \ 56 | \n exec virtuoso-t -c /etc/virtuoso-opensource-6.1/virtuoso.ini' \ 57 | > /etc/services.d/virtuoso/run 58 | 59 | 60 | -------------------------------------------------------------------------------- /inst/docker/cli/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rocker/r-ver:latest 2 | 3 | ## consider removing build deps 4 | RUN apt-get update && apt-get -y install \ 5 | libxml2-dev \ 6 | libcurl4-openssl-dev \ 7 | git \ 8 | automake \ 9 | libtool \ 10 | gtk-doc-tools \ 11 | bison \ 12 | flex \ 13 | libgmp-dev \ 14 | libmhash-dev \ 15 | libgcrypt20-dev \ 16 | libpcre3-dev \ 17 | libv8-dev \ 18 | libjq-dev \ 19 | libpq-dev \ 20 | libdb-dev \ 21 | libsqlite3-dev \ 22 | libmariadbclient-dev \ 23 | librdf-storage-virtuoso \ 24 | unixodbc-dev 25 | 26 | RUN git clone git://github.com/dajobe/raptor.git && \ 27 | cd raptor && \ 28 | ./autogen.sh && \ 29 | make && \ 30 | make install && \ 31 | cd .. && \ 32 | git clone git://github.com/dajobe/rasqal.git && \ 33 | cd rasqal && \ 34 | ./autogen.sh && \ 35 | make && \ 36 | make install && \ 37 | cd .. && \ 38 | git clone git://github.com/dajobe/librdf.git && \ 39 | cd librdf && \ 40 | ./autogen.sh && \ 41 | make && \ 42 | make install 43 | 44 | RUN R -e "install.packages(c('remotes','devtools'))" && \ 45 | R -e "remotes::install_github('ropensci/redland-bindings/R/redland')" && \ 46 | R -e "remotes::install_github('ropensci/rdflib')" 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /inst/docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | 4 | mariadb: 5 | image: mariadb 6 | environment: 7 | - MYSQL_ROOT_PASSWORD=rdflib 8 | 9 | postgres: 10 | image: postgres 11 | environment: 12 | - POSTGRES_PASSWORD=rdflib 13 | 14 | rdflib: 15 | image: ropensci/rdflib 16 | volumes: 17 | - ../../..:/home/rstudio/data 18 | - virtuoso_volume:/var/lib/virtuoso-opensource-6.1/db 19 | working_dir: /home/rstudio/data 20 | depends_on: 21 | - postgres 22 | - mariadb 23 | ports: 24 | - 8787:8787 25 | environment: 26 | - PASSWORD=rdflib 27 | virtuoso: 28 | image: tenforce/virtuoso:1.3.1-virtuoso7.2.2 29 | environment: 30 | SPARQL_UPDATE: "true" 31 | DEFAULT_GRAPH: "http://www.example.com/my-graph" 32 | DBA_PASSWORD: "dba" 33 | VIRT_Parameters_DirsAllowed: "/var/data" 34 | volumes: 35 | - ../extdata:/var/data 36 | 37 | 38 | volumes: 39 | virtuoso_volume: 40 | 41 | 42 | -------------------------------------------------------------------------------- /inst/docker/virtuoso/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:stretch 2 | 3 | ## consider removing build deps 4 | RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq install \ 5 | virtuoso-server 6 | 7 | ## This needs to be on the app container 8 | ## (Both the driver library and the config file) 9 | RUN echo '[Local Virtuoso]\ 10 | \nDriver=/usr/lib/x86_64-linux-gnu/odbc/virtodbc_r.so\ 11 | \nAddress=localhost:1111' >> /etc/odbc.ini 12 | EXPOSE 1111 13 | CMD ["virtuoso-t", "-c", "/etc/virtuoso-opensource-6.1/virtuoso.ini", "-f"] 14 | 15 | -------------------------------------------------------------------------------- /inst/examples/deprecated.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ## Deprecate this strategy in favor of direct result 6 | ## also means we can deprecate type_by_datauri and other utilities 7 | iter_getNextResult <- function(queryResult){ 8 | out <- list() 9 | result <- redland::getNextResult(queryResult) 10 | out <- c(out, result) 11 | while(!is.null(result)){ 12 | result <- redland::getNextResult(queryResult) 13 | out <- c(out, result) 14 | } 15 | out 16 | } 17 | 18 | rectangularize_query_results <- function(out){ 19 | vars <- unique(names(out)) 20 | 21 | X <- lapply(vars, function(v){ 22 | contents <- as.character(out[names(out) == v ]) 23 | values <- type_by_datauri(contents) 24 | 25 | ## use "character" if mixed type column 26 | types <- vapply(values, function(x) class(x)[[1]], character(1)) 27 | u <- unique(types) 28 | if(length(u) == 1){ 29 | values <- unlist(values) 30 | if(u %in% c("Date", "POSIXct")) 31 | class(values) <- unique(types) # Restore date class 32 | } else { 33 | values <- vapply(values, as.character, character(1)) 34 | } 35 | values 36 | }) 37 | 38 | names(X) <- vars 39 | ## Or we could use tibble::as_data_frame for list columns w/ mixed type.. 40 | as.data.frame(X, stringsAsFactors=FALSE) 41 | } 42 | 43 | 44 | 45 | 46 | 47 | #' @importFrom methods as 48 | type_by_datauri <- function(x){ 49 | types <- get_types(x) 50 | r_types <- vapply(types, r_class, character(length(1))) 51 | values <- get_values(x) 52 | 53 | ## Output must be a list since types can differ 54 | out <- vector("list", length = length(values)) 55 | for(i in seq_along(values)){ 56 | out[[i]] <- as(utf8me(values[i]), r_types[[i]]) 57 | 58 | } 59 | out 60 | } 61 | 62 | ## Utilities to coerce return type, if recognized 63 | r_class <- function(x){ 64 | switch(gsub("", "xs:\\1", x), 65 | "xs:decimal" = "numeric", 66 | "xs:string" = "character", 67 | "xs:boolean" = "logical", 68 | "xs:integer" = "integer", 69 | "xs:date" = "Date", 70 | "xs:dateTime" = "POSIXct", 71 | "character" 72 | ) 73 | } 74 | 75 | ## Helper utilitiesfor parsing data URIs 76 | get_values <- function(x) gsub('\"(([^\\^])+)\"\\^*(.*)', "\\1", x) 77 | get_types <- function(x) gsub('\"(([^\\^])+)\"\\^*(.*)', "\\3", x) 78 | #' @importFrom stringi stri_unescape_unicode 79 | # https://stackoverflow.com/questions/48602294 80 | utf8me <- function(x){ 81 | removed_quotes <- gsub('\"', '', x) 82 | stringi::stri_unescape_unicode(removed_quotes) 83 | } 84 | 85 | 86 | ## so that we can do as("2018-02-05", "Date") in type_by_datauri 87 | setAs("character", "Date", function(from) as.Date(as.character(from))) 88 | setAs("character", "POSIXct", function(from) as.POSIXct(as.character(from))) 89 | -------------------------------------------------------------------------------- /inst/examples/rdf-wo-redland.R: -------------------------------------------------------------------------------- 1 | library(nycflights13) 2 | library(dplyr) 3 | 4 | dim(flights) # 336,776 x 19 5 | 6 | as_uri <- function(x, base_uri = "x:") paste0(base_uri, x) 7 | uri_flights <- flights %>% 8 | mutate(tailnum = as_uri(tailnum), 9 | carrier = as_uri(carrier)) 10 | 11 | 12 | df1 <- rdflib:::normalize_table(airlines, key = "carrier", prefix = "x:") 13 | df2 <- rdflib:::normalize_table(planes, key = "tailnum", prefix = "x:") 14 | df3 <- rdflib:::normalize_table(uri_flights, key = NULL, prefix = "x:") 15 | 16 | df <- bind_rows(df1,df2,df3) 17 | 18 | dim(df3) # 6,398,744 x 4 19 | 20 | df %>% 21 | filter(predicate %in% c("carrier", "name", "manufacturer", "model", "dep_delay")) %>% 22 | count(predicate) 23 | 24 | ## We can recover an individual table 25 | df %>% 26 | filter(predicate %in% c("manufacturer", "model")) %>% 27 | select(subject, predicate, object) %>% 28 | tidyr::spread(predicate, object) %>% 29 | rename(tailnum = subject) ## Also need to apply datatype... 30 | ## ... and join manually.... 31 | 32 | 33 | ## What about recovering the "joined" table? 34 | df %>% 35 | filter(predicate %in% c("carrier", "name", "manufacturer", "model", "dep_delay")) %>% 36 | select(subject, predicate, object) %>% tidyr::spread(predicate, object) %>% 37 | filter(!is.na(carrier)) 38 | 39 | 40 | ## Compare to pure approach on original tables 41 | flights %>% 42 | left_join(airlines, by = "carrier") %>% 43 | left_join(planes, by = "tailnum") %>% 44 | select(carrier, name, manufacturer, model, dep_delay) %>% 45 | distinct() 46 | 47 | #### All fits in memory anyway 48 | #library(MonetDBLite) 49 | #library(DBI) 50 | #triplestore <- rappdirs::user_data_dir("rdflib") 51 | #con <- dbConnect(MonetDBLite::MonetDBLite(), triplestore) 52 | 53 | # Could use append=TRUE instead to extend triplestore later 54 | #DBI::dbWriteTable(con, "flights", df, overwrite = TRUE) 55 | 56 | 57 | ## size as flat files on disk: 58 | readr::write_tsv(flights, "flights.tsv") # 29.6 MB 59 | readr::write_tsv(df, "triplestore.tsv") # 319 MB 60 | readr::write_tsv(df, "triplestore.tsv.bz2") # 17 MB 61 | 62 | 63 | -------------------------------------------------------------------------------- /inst/examples/storage_types.R: -------------------------------------------------------------------------------- 1 | ## Experimental testing of different storage backends in redland: 2 | 3 | library(redland) 4 | world <- new("World") 5 | 6 | ## BDB 7 | bdb_storage <- new("Storage", world, "hashes", name = "db1", 8 | options = "new='yes',hash-type='bdb',dir='.'") 9 | model <- new("Model", world = world, storage = bdb_storage, options = "") 10 | 11 | ## SQLITE 12 | sqlite_storage <- new("Storage", world, "sqlite", name = "sqlite1", options = "new='yes'") 13 | 14 | 15 | ## POSTGRES 16 | ## Needs postgres backend running 17 | postgres_storage <- new("Storage", world, "postgresql", name = "postgres1", 18 | options = "new='yes',host='postgres',user='postgres','password='rdflib'") 19 | 20 | ## MYSQL 21 | ## Needs mysql backend running 22 | mysql_store <- new("Storage", world, "mysql", name = "mysql1", 23 | options = "new='yes',host='mariadb',user='root',password='rdflib',database='db'") 24 | 25 | ## VIRTUOSO 26 | ## Needs virtuoso backend running 27 | virtuoso_storage <- new("Storage", world, "virtuoso", name = "db1", 28 | "dsn='Local Virtuoso',user='demo',password='demo'") 29 | 30 | 31 | ## Works, in memory, serializes to an rdf/xml file called thing.rdf when freed. 32 | ## Not indexed, so will be slow. Suitable for small models. 33 | file_storage <- new("Storage", world, "file", "thing.rdf", "") 34 | storage <- file_storage 35 | model <- new("Model", world = world, storage = storage, options = "") 36 | 37 | ## Works, fast write, not indexed, good for only small models, 38 | ## no reason to use this instead of hash-based memory (which is indexed) 39 | memory_storage <- new("Storage", world, "memory", "", "") 40 | storage <- memory_storage 41 | model <- new("Model", world = world, storage = storage, options = "") 42 | 43 | 44 | ## Testing 45 | library(rdflib) 46 | rdf <- structure(list(world = world, model = model, storage = storage), 47 | class = "rdf") 48 | rdf_add(rdf, 49 | subject="http://www.dajobe.org/", 50 | predicate="http://purl.org/dc/elements/1.1/language", 51 | object="en") 52 | rdf 53 | -------------------------------------------------------------------------------- /inst/examples/tidy_schema.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | #' Tidy Schema 4 | #' 5 | #' Construct a SPARQL query in which properties (predicates) become column headings 6 | #' and values (objects) become entries of individual cells. 7 | #' 8 | #' @param ... names of the properties that should make up columns in the table 9 | #' @param columns Alternatively, supply a vector of property names. 10 | #' @param prefix the URI string to prefix before the property names to give 11 | #' fully-resolved properties. 12 | #' @param na.rm logical, default TRUE. Will not return a row for any 13 | #' subject that does not have a object value matching the schema. 14 | #' @examples 15 | #' 16 | #' sparql <- table_schema("Species", "Sepal.Length", prefix = "iris") 17 | #' rdf_query(rdf, sparql) 18 | #' 19 | #' ## use columns arg for an existing vector of names. 20 | #' columns <- names(iris) 21 | #' sparql <- tidy_schema(columns = columns, prefix = "iris") 22 | #' rdf_query(rdf, sparql) 23 | #' 24 | #' ## use na.rm = FALSE to include NA if variable is not defined for some observations 25 | #' sparql <- tidy_schema("Species", "Sepal.Length", "Sepal.Color", 26 | #' prefix = "iris", na.rm=FALSE) 27 | #' rdf_query(rdf, sparql) 28 | tidy_schema <- function(..., columns = NULL, prefix=NULL, na.rm = TRUE){ 29 | if(is.null(columns)){ 30 | columns <- c(...) 31 | } 32 | 33 | if(!is.null(prefix)){ 34 | attributes <- paste0("<",prefix, ":", columns, ">") 35 | } else { 36 | attributes <- paste0("<", columns, ">") 37 | } 38 | ## Replace forbidden characters with "_", 39 | ## See spec: https://www.w3.org/TR/rdf-sparql-query/#rVARNAME 40 | vars <- gsub("[^a-zA-Z1-9_]","_", basename(columns)) 41 | select <- paste0("?", vars) 42 | 43 | where <- paste("?s", attributes, select) 44 | if(!na.rm) 45 | where <- paste("OPTIONAL {", where, "}") 46 | else 47 | where <- paste(where, ".") 48 | where <- paste(where, collapse = "\n") 49 | query <- paste("SELECT", paste0(select, collapse = " "), 50 | "\nWHERE {\n", where, "\n}") 51 | query 52 | } 53 | 54 | 55 | #sparql <- table_schema("Sepal.Length", "Sepal.Width", 56 | # "Petal.Length", "Petal.Width", 57 | # "Species", prefix="iris") 58 | #sparql <- table_schema(columns=names(iris), prefix="iris") 59 | #rdf_query(rdf, sparql) %>% as_tibble() 60 | -------------------------------------------------------------------------------- /inst/examples/virtuoso-direct.R: -------------------------------------------------------------------------------- 1 | library(DBI) 2 | library(odbc) 3 | 4 | virtuoso <- dbConnect(odbc::odbc(), 5 | driver = "Virtuoso", 6 | uid = "dba", 7 | pwd = "dba", 8 | host = "virtuoso", 9 | port = "1111") 10 | 11 | ## It's alive! 12 | virtuoso 13 | 14 | ## Bulk import -- fast! 15 | dbGetQuery(virtuoso, "ld_dir('/var/data/', '*.nq', 'rdflib')" ) 16 | dbGetQuery(virtuoso, "rdf_loader_run()" ) 17 | 18 | 19 | ## List all graphs -- look, we have one called 'rdflib' now! 20 | dbGetQuery(virtuoso, 21 | "SPARQL SELECT DISTINCT ?g WHERE { GRAPH ?g {?s ?p ?o} } ORDER BY ?g" 22 | ) 23 | 24 | 25 | ## Select FROM GRAPH 26 | dbGetQuery(virtuoso, "SPARQL SELECT * FROM WHERE { {?s ?p ?o} } LIMIT 10") 27 | 28 | dbGetQuery(virtuoso, "SPARQL SELECT * FROM WHERE { {?s ?o} } LIMIT 10") 29 | 30 | ## Wow, we can write standard tables into Virtuoso too... 31 | #dbWriteTable(virtuoso, "iris", iris) # Dots not allowed in column names 32 | dbWriteTable(virtuoso, "mtcars", mtcars) 33 | dbListTables(virtuoso, table_name = "mt%") 34 | dbReadTable(virtuoso, "mtcars") 35 | 36 | 37 | ## Clear graph 38 | dbGetQuery(virtuoso, "SPARQL CLEAR GRAPH ") 39 | 40 | 41 | ## Counting triples in each different graph... 42 | q <- "SPARQL SELECT ?g ?s ?p ?o WHERE { GRAPH ?g {?s ?p ?o} }" 43 | df <- dbGetQuery(virtuoso, q) 44 | library(dplyr) 45 | df %>% count(g) 46 | 47 | 48 | 49 | #remotes::install_github("ropensci/rdflib") 50 | library(rdflib) 51 | library(nycflights13) 52 | library(dplyr) 53 | ## prefix foreign keys 54 | uri_flights <- flights %>% 55 | mutate(tailnum = paste0("planes:", tailnum), 56 | carrier = paste0("airlines:", carrier)) 57 | 58 | h <- here::here("data/rdflib/inst/extdata") 59 | write_nquads(airlines, file.path(h, "airlines.nq"), key = "carrier", prefix = "airlines:") 60 | write_nquads(planes, file.path(h, "planes.nq"), key = "tailnum", prefix = "planes:") 61 | write_nquads(uri_flights, file.path(h, "uri_flights.nq"), prefix = "flights:") 62 | 63 | ## Bulk import -- fast! 64 | dbGetQuery(virtuoso, "ld_dir('/var/data/', '*.nq', 'rdflib')" ) 65 | dbGetQuery(virtuoso, "rdf_loader_run()" ) 66 | 67 | 68 | 69 | 70 | 71 | remotes::install_github("ropensci/rdflib") 72 | library(rdflib) 73 | triplestore <- rdf(storage = "virtuoso", 74 | user = "dba", 75 | password = "dba", 76 | host = "virtuoso:1111" 77 | ) 78 | triplestore 79 | #write_nquads(iris, "iris.nq", prefix = "iris") 80 | #read_nquads("iris.nq", rdf = triplestore) 81 | ## Works! 82 | triplestore 83 | 84 | ## We can query with rdflib too! 85 | query <- "SELECT ?s ?p ?o WHERE {?s ?p ?o } LIMIT 10" 86 | out <- rdf_query(triplestore, query) 87 | rdf_free(triplestore) 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /inst/extdata/ex.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | urn:issn:2045-7758 7 | Ecology and Evolution 8 | 2045-7758 9 | 2045-7758 10 | 11 | 12 | 2016-08-18 13 | 6434 14 | 10.1002/ece3.2314 15 | 6425 16 | 6 17 | After the games are over: life-history trade-offs drive dispersal attenuation following range expansion 18 | 10.1002/ece3.2314 19 | 20 | 6 21 | 22 | Wiley-Blackwell 23 | 10.1002/ece3.2314 24 | 25 | 26 | Benjamin L. Phillips 27 | Phillips 28 | Benjamin L. 29 | 30 | 31 | 32 | 33 | T. Alex Perkins 34 | Perkins 35 | T. Alex 36 | 37 | 38 | 39 | 40 | Carl Boettiger 41 | Boettiger 42 | Carl 43 | 44 | 45 | 6425 46 | 6434 47 | 48 | 49 | -------------------------------------------------------------------------------- /inst/extdata/ex2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Jane Doe 8 | 9 | 10 | 11 | 12 | 13 | Professor 14 | 15 | 16 | (425) 123-4567 17 | 18 | 19 | -------------------------------------------------------------------------------- /inst/extdata/person.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": "http://schema.org", 3 | "@type": "Person", 4 | "@id": "https://orcid.org/0000-0002-1642-628X", 5 | "givenName": "Carl", 6 | "familyName": "Boettiger", 7 | "address": { 8 | "@type": "PostalAddress", 9 | "streetAddress": "130 Mulford Hall #3114", 10 | "addressLocality": "Berkeley", 11 | "addressRegion": "CA", 12 | "postalCode": "94720-3114" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /inst/extdata/person.nq: -------------------------------------------------------------------------------- 1 | _:b0 . 2 | "Carl" . 3 | _:b0 "Berkeley" . 4 | _:b0 . 5 | _:b0 "130 Mulford Hall #3114" . 6 | "Boettiger" . 7 | _:b0 "94720-3114" . 8 | _:b0 "CA" . 9 | . 10 | -------------------------------------------------------------------------------- /inst/notebook/libs/remark-css/default-fonts.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Yanone+Kaffeesatz); 2 | @import url(https://fonts.googleapis.com/css?family=Droid+Serif:400,700,400italic); 3 | @import url(https://fonts.googleapis.com/css?family=Source+Code+Pro:400,700); 4 | 5 | body { font-family: 'Droid Serif', 'Palatino Linotype', 'Book Antiqua', Palatino, 'Microsoft YaHei', 'Songti SC', serif; } 6 | h1, h2, h3 { 7 | font-family: 'Yanone Kaffeesatz'; 8 | font-weight: normal; 9 | } 10 | .remark-code, .remark-inline-code { font-family: 'Source Code Pro', 'Lucida Console', Monaco, monospace; } 11 | -------------------------------------------------------------------------------- /inst/notebook/libs/remark-css/default.css: -------------------------------------------------------------------------------- 1 | a, a > code { 2 | color: rgb(249, 38, 114); 3 | text-decoration: none; 4 | } 5 | .footnote { 6 | position: absolute; 7 | bottom: 3em; 8 | padding-right: 4em; 9 | font-size: 90%; 10 | } 11 | .remark-code-line-highlighted { background-color: #ffff88; } 12 | 13 | .inverse { 14 | background-color: #272822; 15 | color: #d6d6d6; 16 | text-shadow: 0 0 20px #333; 17 | } 18 | .inverse h1, .inverse h2, .inverse h3 { 19 | color: #f3f3f3; 20 | } 21 | /* Two-column layout */ 22 | .left-column { 23 | color: #777; 24 | width: 20%; 25 | height: 92%; 26 | float: left; 27 | } 28 | .left-column h2:last-of-type, .left-column h3:last-child { 29 | color: #000; 30 | } 31 | .right-column { 32 | width: 75%; 33 | float: right; 34 | padding-top: 1em; 35 | } 36 | .pull-left { 37 | float: left; 38 | width: 47%; 39 | } 40 | .pull-right { 41 | float: right; 42 | width: 47%; 43 | } 44 | .pull-right ~ * { 45 | clear: both; 46 | } 47 | img, video, iframe { 48 | max-width: 100%; 49 | } 50 | blockquote { 51 | border-left: solid 5px lightgray; 52 | padding-left: 1em; 53 | } 54 | table { 55 | margin: auto; 56 | border-top: 1px solid #666; 57 | border-bottom: 1px solid #666; 58 | } 59 | table thead th { border-bottom: 1px solid #ddd; } 60 | th, td { padding: 5px; } 61 | thead, tfoot, tr:nth-child(even) { background: #eee } 62 | 63 | @page { margin: 0; } 64 | @media print { 65 | .remark-slide-scaler { 66 | width: 100% !important; 67 | height: 100% !important; 68 | transform: scale(1) !important; 69 | top: 0 !important; 70 | left: 0 !important; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /inst/notebook/profile_performance.Rmd: -------------------------------------------------------------------------------- 1 | 2 | ```{r} 3 | library(nycflights13) 4 | library(dplyr) 5 | library(rdflib) 6 | ``` 7 | 8 | 9 | 10 | ```{r} 11 | source(system.file("examples/as_rdf.R", package="rdflib")) 12 | ``` 13 | 14 | 15 | We need to set `rdflib` option to use disk-based rather than in-memory storage, 16 | or it appears that `redland` throws an error (even when the machine has sufficient memory!?) 17 | when importing the 336,776 rows of the `flights` table. 18 | 19 | Note: if BDB is not available (e.g. `berkeley-db` libraries were not found when `redland` was built from source), 20 | then this will fallback on in-memory storage and this vignette will use an abridged version of the flights table. 21 | 22 | ```{r} 23 | options(rdflib_storage = "BDB") 24 | options(rdflib_storage = "memory") 25 | ``` 26 | 27 | 28 | ## Tidyverse Style 29 | 30 | Operations in `dplyr` on the `nyflights13` dataset are easy to write and fast to execute, (in memory or on disk): 31 | 32 | ```{r} 33 | df <- flights %>% 34 | left_join(airlines) %>% 35 | left_join(planes, by="tailnum") %>% 36 | select(carrier, name, manufacturer, model) %>% 37 | distinct() 38 | head(df) 39 | ``` 40 | 41 | 42 | 43 | Use a smaller dataset if we do not have a BDB backend: 44 | 45 | ```{r} 46 | #if(!rdf_has_bdb()){ 47 | flights <- flights %>% 48 | filter(distance > 3000) # try smaller dataset 49 | #} 50 | ``` 51 | 52 | 53 | Keys, including foreign keys, must be represented as URIs and not literal strings. 54 | 55 | ```{r} 56 | as_uri <- function(x, base_uri = "x:") paste0(base_uri, x) 57 | 58 | uri_flights <- flights %>% 59 | mutate(tailnum = as_uri(tailnum), 60 | carrier = as_uri(carrier)) 61 | 62 | 63 | ``` 64 | 65 | 66 | 67 | # RDF Serialization Strategies for large data.frames 68 | 69 | We consider a variety of strategies for actually importing `data.frames` into RDF: 70 | 71 | - **Via `rdf_add()`**: Iterate over each row/cell with calls to `rdf_add` 72 | - **Via JSON-LD**: Coerce the `data.frame` to JSON (via `jsonlite::toJSON(force=TRUE)`), and parse as JSON-LD 73 | - **Via write.table()**` we `tidyr::gather()` and then hack such that we can call `write.table` on a `data.frame` to get an `nquads` text file 74 | 75 | As we'll see, only the third solution has adequate performance here. `rdf_add()` requires an initializer call inside each `redland::addStatement`, 76 | which takes a considerable fraction of a second. Multiply that by the number of cells in the `data.frame` and things do not scale. 77 | 78 | `jsonlite` can convert even the large `data.frame`s into JSON reasonably quickly. 79 | `jsonld::jsonld_to_rdf()` is then also acceptably fast (despite being Javascript) at converting this to `nquads`, 80 | but unfortunately fails dramatically (i.e. `segfault`) when attempting to serialize the flights data. (Recall we can only get into redland RDF model from JSON-LD via nquads). 81 | Perhaps that is due to some particular data in `flights` table, but it's not obvious. 82 | Otherwise, this approach has lots to recommend it. One nice feature about this approach is that it applies to almost 83 | any R object (e.g. any list object), though some care should be taken with names and URIs, as always. Another nice 84 | feature is that it handles the basic data types automatically -- JSON already has types for logical, double, integer, 85 | and string, and these will get automatically encoded with the datatype URIs by the built-in `jsonld_to_rdf` algorithm. 86 | 87 | 88 | The third approach is something of a poor-man's hack to the second approach. A single call to `rdf_parse()` results in only 89 | a single call through the redland C API to acually read in all the triples -- so unlike the `rdf_add()` approach, all the work 90 | is being done at the C level -- the amount of R code involved doesn't at all depend on the number of triples. This is still 91 | not nearly as fast as reading in large data.frames with `readr` or even with `read.table()`, but is probably as fast as we can get. 92 | The trick then is to serialize the data.frame into an RDF format as quickly as possible. We can write large `data.frame`s to text 93 | files rather quickly with good ol `write.table()`, and after all `nquads` looks a lot like a space separated, four-column text file, 94 | modulo a little markup to identify URIs and datatypes. (`readr::write_delim` might be faster, but it's automatic quoting rules appear 95 | to be incompatible with the `nquads` use of quotations.) We're left manually encoding the URI strings and the datatypes onto our 96 | `data.frame` in advance (which requires more nuiance to handle default data types, blank nodes and missing values than I've currently 97 | implemented), but as a proof of principle here this approach is sufficiently fast, as we will now see. 98 | 99 | 100 | ```{r} 101 | ## generic list-based conversion via JSON-LD 102 | rdf_planes_from_list <- as_rdf.list(planes) 103 | ``` 104 | 105 | 106 | Let's do the smaller tables first. We declare which column is the `key` (i.e. `subject`), 107 | and we define a `base_uri` prefix which we use to make sure column names and subjects are treated as URIs. 108 | With tables that have only tens of thousands of cells (triples) this is pretty fast: 109 | 110 | ```{r} 111 | x1 <- as_rdf(airlines, "carrier", "x:") 112 | x2 <- as_rdf(airports, "faa", "x:") ## a few funny chars, UTF8 issues? 113 | x3 <- as_rdf(planes, "tailnum", "x:") 114 | 115 | x <- c(rdf(), x1,x2,x3) 116 | ``` 117 | 118 | 119 | SPARQL queries on the resulting data are also pretty fast: 120 | 121 | 122 | 123 | 124 | ```{r} 125 | sparql <- 126 | 'SELECT ?model 127 | WHERE { 128 | ?tailnum ?carrier . 129 | ?tailnum ?model 130 | }' 131 | 132 | out <- rdf_query(x1, sparql) 133 | head(out) 134 | ``` 135 | 136 | 137 | 138 | 139 | Big table via poor-man's `nquads` 165 seconds if this is the full table: 140 | 141 | ```{r} 142 | system.time( 143 | x4 <- as_rdf(uri_flights, NULL, "x:") 144 | ) 145 | ``` 146 | 147 | 148 | The json-ld approach just appears to crash, so we won't run that: 149 | 150 | ```{r} 151 | ## nope, the jsonld method appears to crash R... 152 | #system.time( 153 | # x4 <- as_rdf.list(na.omit(flights)) 154 | #) 155 | ``` 156 | 157 | 158 | We can join all of these: 159 | 160 | ```{r} 161 | rdf <- c(rdf(), x1,x2,x3,x4) 162 | ``` 163 | 164 | 165 | 166 | Separate queries: This proves very slow on the full data! Would be much faster if we did not have to iterate over getNextResult but could parse all results as a document. Hopefully this change is coming to `redland` R library soon! 167 | 168 | ```{r} 169 | sparql <- 170 | 'SELECT ?tailnum ?dep_delay ?carrier 171 | WHERE { 172 | ?flight ?tailnum . 173 | ?flight ?dep_delay . 174 | ?flight ?carrier 175 | }' 176 | 177 | system.time( 178 | 179 | f1 <- rdf_query(rdf, sparql) 180 | ) 181 | ``` 182 | 183 | ```{r} 184 | sparql <- 185 | 'SELECT ?tailnum ?model ?manufacturer 186 | WHERE { 187 | ?tailnum ?manufacturer . 188 | ?tailnum ?model 189 | }' 190 | f2 <- rdf_query(rdf, sparql) 191 | 192 | tmp <- inner_join(f1,f2) 193 | ``` 194 | 195 | 196 | 197 | 198 | ```{r} 199 | s <- 200 | 'SELECT ?carrier ?name ?manufacturer ?model 201 | WHERE { 202 | ?flight ?tailnum . 203 | ?tailnum ?manufacturer . 204 | ?tailnum ?model . 205 | ?flight ?carrier . 206 | ?carrier ?name 207 | }' 208 | 209 | out2 <- rdf_query(rdf, s) 210 | head(out2) 211 | ``` 212 | 213 | -------------------------------------------------------------------------------- /inst/notebook/sparql_query_examples_vita.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "rdflib Introduction" 3 | author: "Carl Boettiger" 4 | date: "`r Sys.Date()`" 5 | output: 6 | rmarkdown::html_vignette: 7 | df_print: paged 8 | vignette: > 9 | %\VignetteIndexEntry{rdflib Introduction} 10 | %\VignetteEngine{knitr::rmarkdown} 11 | %\VignetteEncoding{UTF-8} 12 | 13 | --- 14 | 15 | 16 | 17 | `rdflib` is really just a lightweight wrapper around two existing R packages: `redland`, and `jsonld`, which themselves are (less trivial) wrappers around existing libraries (the redland C library, and the JSON-LD javascript implementation) which themselves are instances of a set of W3C Standards for the representation of linked data. `rdflib` has two key features: a simpler, higher-level interface for the common tasks performed in the `redland` library (user does not have to manage `world`, `model` and `storage` objects by default just to perform standard operations and conversions), and integration between the now popular `json-ld` serialization, which is not part of the `redland` library. 18 | 19 | 20 | ```{r setup, message=FALSE} 21 | library(rdflib) 22 | library(magrittr) # pipes 23 | 24 | ## JSON toolkit 25 | library(jsonld) 26 | library(jsonlite) 27 | library(jqr) 28 | 29 | ## For accessing some remote data sources 30 | library(httr) 31 | library(xml2) 32 | library(readr) 33 | 34 | ## for some typical data processing 35 | library(dplyr) 36 | library(lubridate) 37 | 38 | ``` 39 | 40 | 41 | 42 | ## SPARQL queries on JSON-LD data 43 | 44 | One example of this utility is the ability to perform graph queries using SPARQL on JSON-LD datasets. The SPARQL query language is analgous to other query languages such as SQL, but instead of working on an existing set of tables in a relational database, we can query data from a triplestore. 45 | 46 | This is sometimes called "schema on read", since our query will define the schema (i.e. the structure or skeleton of the `data.frame`) our data is returned in. Because SPARQL is a graph query language, this makes it easy to construct a query that would be cumbersome in SQL or even other recursive tree queries like `jq`, which both would require some knowledge of how the stored data is organized. 47 | 48 | To illustrate this, consider the following example. NSF asks me to list all of my co-authors within the past four years as conflicts of interest (COI). Here is a query that for all papers where I am an author, returns a table of given name, family name and year of publication: 49 | 50 | ```{r} 51 | ex <- system.file("extdata/vita.json", package="rdflib") 52 | vita <- rdf_parse(ex, "jsonld") 53 | 54 | sparql <- 55 | 'PREFIX schema: 56 | 57 | SELECT ?coi_given ?coi_family ?year 58 | 59 | WHERE { 60 | ?paper a schema:ScholarlyArticle . 61 | ?paper schema:author ?authors . 62 | ?paper schema:dateCreated ?year . 63 | ?authors schema:familyName ?coi_family . 64 | OPTIONAL { ?authors schema:givenName ?coi_given . } 65 | 66 | FILTER ( ?coi_family != "Boettiger" ) 67 | } 68 | ' 69 | 70 | coi <- vita %>% rdf_query(sparql) 71 | ``` 72 | 73 | ```{r echo=FALSE} 74 | DT::datatable(coi) 75 | ``` 76 | 77 | 78 | Now we have rectangular data, we can tidy things up a bit more. (In principle I believe we could have done this in SPARQL as well) 79 | 80 | ```{r} 81 | coi2 <- 82 | coi %>% 83 | ## join names, year as Date 84 | mutate(year = as.Date(year), name = paste0(coi_family, ", ", coi_given)) %>% 85 | ## interaction in last 4 years 86 | filter(year > lubridate::today() - lubridate::years(3)) %>% 87 | ## For each person, list only most recent date 88 | group_by(name) %>% 89 | summarise(year = max(year)) 90 | 91 | 92 | ``` 93 | 94 | ```{r echo=FALSE} 95 | DT::datatable(coi2) 96 | ``` 97 | 98 | 99 | Yay, that's wasn't so bad. Rectangling JSON without a graph query is not as easy. This can be immensely frustrating to do using basic iteration operations with `purrr`, even with it's powerful syntax. Rectangling is a bit better with a tree-based query language, like a `jq` query. The only limitation here is that we have to know just a little about how our data is structured, since there are multiple tree structures that correspond to the same graph (or we could just use JSON-LD frame first, but that adds another step in the puzzle.) 100 | 101 | Here's the same extraction on the same data, but with a `jq` query: 102 | 103 | ```{r} 104 | coi_jq <- 105 | readr::read_file(ex) %>% 106 | jqr::jq( 107 | '."@reverse".author[] | 108 | { year: .dateCreated, 109 | author: .author[] | [.givenName, .familyName] | join(" ") 110 | }') %>% 111 | jqr::combine() %>% 112 | jsonlite::fromJSON() 113 | 114 | ``` 115 | 116 | ```{r} 117 | coi3 <- 118 | coi_jq %>% 119 | mutate(year = as.Date(year)) %>% 120 | filter(year > lubridate::today() - lubridate::years(3)) %>% 121 | filter(!grepl("Boettiger", author)) %>% 122 | ## For each person, list only most recent date 123 | group_by(author) %>% 124 | summarise(year = max(year)) 125 | ``` 126 | 127 | ```{r echo=FALSE} 128 | DT::datatable(coi3) 129 | ``` 130 | 131 | 132 | 133 | 134 | ## Turning RDF-XML into more friendly JSON 135 | 136 | 137 | `rdflib` can also be useful as quick and lossless way to convert parse common data formats (e.g. RDF XML) into something more R-friendly. In this vignette, we illustrate how this might work in a simple example of some citation data returned in RDF-XML format from CrossRef. 138 | 139 | Let's begin by reading in some `RDF/XML` data from CrossRef by querying a DOI and requesting `rdf+xml` MIME type (via Content Negotiation): 140 | 141 | ```{r eval=FALSE} 142 | xml <- "ex.xml" 143 | 144 | "https://doi.org/10.1002/ece3.2314" %>% 145 | httr::GET(httr::add_headers(Accept="application/rdf+xml")) %>% 146 | httr::content(as = "parsed", type = "application/xml") %>% 147 | xml2::write_xml(xml) 148 | ``` 149 | 150 | ```{r include=FALSE} 151 | xml<- system.file("extdata/ex.xml", package="rdflib") 152 | ``` 153 | 154 | Our `rdflib` functions perform the simple task of parsing this `rdfxml` file into R (as a `redland` `rdf` class object) and then writing it back out in `jsonld` serialization: 155 | 156 | 157 | ```{r} 158 | rdf_parse(xml, "rdfxml") %>% 159 | rdf_serialize("ex.json", "jsonld") 160 | ``` 161 | 162 | 163 | and we now have JSON file. We can clean this file up a bit by replacing the long URIs with short prefixes by "compacting" the file into a specific JSON-LD context. FOAF, OWL, and Dublin Core are all recognized by schema.org, so we need not declare them at all here. PRISM and BIBO ontologies are not, so we simply declare them as additional prefixes: 164 | 165 | ```{r} 166 | context <- 167 | '{ "@context": [ 168 | "http://schema.org", 169 | { 170 | "prism": "http://prismstandard.org/namespaces/basic/2.1/", 171 | "bibo": "http://purl.org/ontology/bibo/" 172 | }] 173 | }' 174 | json <- jsonld_compact("ex.json", context) 175 | 176 | ``` 177 | 178 | 179 | ```{r include=FALSE} 180 | unlink("ex.xml") 181 | unlink("ex.json") 182 | ``` 183 | -------------------------------------------------------------------------------- /man/as_rdf.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/as_rdf.R 3 | \name{as_rdf} 4 | \alias{as_rdf} 5 | \title{Coerce an object into RDF} 6 | \usage{ 7 | as_rdf( 8 | x, 9 | rdf = NULL, 10 | prefix = NULL, 11 | base = getOption("rdf_base_uri", "localhost://"), 12 | context = NULL, 13 | key_column = NULL 14 | ) 15 | } 16 | \arguments{ 17 | \item{x}{an object to coerce into RDF (list, list-like, or data.frame)} 18 | 19 | \item{rdf}{An existing rdf object, (by default a new object will be initialized)} 20 | 21 | \item{prefix}{A default vocabulary (URI prefix) to assume for all predicates} 22 | 23 | \item{base}{A base URI to assume for blank subject nodes} 24 | 25 | \item{context}{a named list mapping any string to a URI} 26 | 27 | \item{key_column}{name of a column which should be 28 | treated as the primary key in a table. must be unique} 29 | } 30 | \description{ 31 | Coerce an object into RDF 32 | } 33 | \examples{ 34 | as_rdf(mtcars) 35 | as_rdf(list(repo = "rdflib", owner = list("id", "ropensci"))) 36 | } 37 | -------------------------------------------------------------------------------- /man/c.rdf.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rdf_methods.R 3 | \name{c.rdf} 4 | \alias{c.rdf} 5 | \title{Concatenate rdf Objects.} 6 | \usage{ 7 | \method{c}{rdf}(...) 8 | } 9 | \arguments{ 10 | \item{...}{objects to be concatenated} 11 | } 12 | \description{ 13 | All subsequent rdf objects will be appended to the first rdf object 14 | Note: this does not free memory from any of the individual rdf objects 15 | Note: It is generally better to avoid the use of this function by passing 16 | an existing rdf object to and rdf_parse or rdf_add objects. Multiple active 17 | rdf objects can cause problems when using disk-based storage backends. 18 | } 19 | -------------------------------------------------------------------------------- /man/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/man/figures/logo.png -------------------------------------------------------------------------------- /man/rdf.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rdf.R 3 | \name{rdf} 4 | \alias{rdf} 5 | \title{Initialize an \code{rdf} Object} 6 | \usage{ 7 | rdf( 8 | storage = c("memory", "BDB", "sqlite", "postgres", "mysql", "virtuoso"), 9 | host = NULL, 10 | port = NULL, 11 | user = NULL, 12 | password = NULL, 13 | database = NULL, 14 | charset = NULL, 15 | dir = NULL, 16 | dsn = "Local Virtuoso", 17 | name = "rdflib", 18 | new_db = FALSE, 19 | fallback = TRUE 20 | ) 21 | } 22 | \arguments{ 23 | \item{storage}{Storage backend to use; see details} 24 | 25 | \item{host}{host address for mysql, postgres, or virtuoso storage} 26 | 27 | \item{port}{port for mysql (mysql storage defaults to mysql standard port, 3306) 28 | or postgres (postgres storage defaults to postgres standard port, 4321)} 29 | 30 | \item{user}{user name for postgres, mysql, or virtuoso} 31 | 32 | \item{password}{password for postgres, mysql, or virtuoso} 33 | 34 | \item{database}{name of the database to be created/used} 35 | 36 | \item{charset}{charset for virtuoso database, if desired} 37 | 38 | \item{dir}{directory of where to write sqlite or berkeley database.} 39 | 40 | \item{dsn}{Virtuoso dsn, either "Local Virtuoso" or "Remote Virtuoso"} 41 | 42 | \item{name}{name for the storage object created. Default is usually fine.} 43 | 44 | \item{new_db}{logical, default FALSE. Create new database or connect to existing?} 45 | 46 | \item{fallback}{logical, default TRUE. If requested storage system cannot initialize, 47 | should \code{rdf()} fall back on memory (default) or throw an error (fallback=FALSE)?} 48 | } 49 | \value{ 50 | an rdf object 51 | } 52 | \description{ 53 | Initialize an \code{rdf} Object 54 | } 55 | \details{ 56 | an rdf Object is a list of class 'rdf', consisting of 57 | three pointers to external C objects managed by the redland library. 58 | These are the \code{world} object: basically a top-level pointer for 59 | all RDF models, and a \code{model} object: a collection of RDF statements, 60 | and a \code{storage} object, indicating how these statements are stored. 61 | 62 | \code{rdflib} defaults to an in-memory hash-based storage structure. 63 | which should be best for most use cases. For very large triplestores, 64 | disk-based storage will be necessary. Enabling external storage devices 65 | will require additional libraries and custom compiling. See the storage 66 | vignette for details. 67 | } 68 | \examples{ 69 | x <- rdf() 70 | 71 | } 72 | -------------------------------------------------------------------------------- /man/rdf_add.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rdf_add.R 3 | \name{rdf_add} 4 | \alias{rdf_add} 5 | \title{Add RDF Triples} 6 | \usage{ 7 | rdf_add( 8 | rdf, 9 | subject, 10 | predicate, 11 | object, 12 | subjectType = as.character(NA), 13 | objectType = as.character(NA), 14 | datatype_uri = as.character(NA) 15 | ) 16 | } 17 | \arguments{ 18 | \item{rdf}{an rdf object} 19 | 20 | \item{subject}{character string containing the subject} 21 | 22 | \item{predicate}{character string containing the predicate} 23 | 24 | \item{object}{character string containing the object} 25 | 26 | \item{subjectType}{the Node type of the subject, i.e. "uri", "blank"} 27 | 28 | \item{objectType}{the Node type of the object, i.e. "literal", "uri", "blank"} 29 | 30 | \item{datatype_uri}{the datatype URI to associate with a object literal value} 31 | } 32 | \value{ 33 | Silently returns the updated RDF graph (rdf object). 34 | Since the rdf object simply contains external pointers 35 | to the model object in C code, note that the input object is modified 36 | directly, so you need not assign the output of rdf_add() to anything. 37 | } 38 | \description{ 39 | add a triple (subject, predicate, object) to the RDF graph 40 | } 41 | \details{ 42 | \code{rdf_add()} will automatically 'duck type' nodes (if looks like a duck...). 43 | That is, strings that look like URIs will be declared as URIs. (See 44 | \href{https://en.wikipedia.org/wiki/Uniform_Resource_Identifier}{URI}). 45 | Predicate should always be a URI (e.g. URL or a \code{prefix:string}), 46 | cannot be blank or literal. Subjects that look like strings will be 47 | treated as \href{https://en.wikipedia.org/wiki/Blank_node}{Blank Nodes} (i.e. 48 | will be prefixed with \verb{_:}). An empty subject, \code{""}, will create a 49 | blank node with random name. Objects that look like URIs will be 50 | typed as resource nodes, otherwise as literals. An empty object \code{""} 51 | will be treated as blank node. Set \code{subjectType} or \code{objectType} 52 | explicitly to override this behavior, e.g. to treat an object URI 53 | as a literal string. NAs are also treated as blank nodes in subject 54 | or object See examples for details. 55 | } 56 | \examples{ 57 | rdf <- rdf() 58 | rdf_add(rdf, 59 | subject="http://www.dajobe.org/", 60 | predicate="http://purl.org/dc/elements/1.1/language", 61 | object="en") 62 | 63 | ## non-URI string in subject indicates a blank subject 64 | ## (prefixes to "_:b0") 65 | rdf_add(rdf, "b0", "http://schema.org/jobTitle", "Professor") 66 | 67 | ## identically a blank subject. 68 | ## Note rdf is unchanged when we add the same triple twice. 69 | rdf_add(rdf, "b0", "http://schema.org/jobTitle", "Professor", 70 | subjectType = "blank") 71 | 72 | ## blank node with empty string creates a default blank node id 73 | rdf_add(rdf, "", "http://schema.org/jobTitle", "Professor") 74 | 75 | 76 | ## Subject and Object both recognized as URI resources: 77 | rdf_add(rdf, 78 | "https://orcid.org/0000-0002-1642-628X", 79 | "http://schema.org/homepage", 80 | "http://carlboettiger.info") 81 | 82 | ## Force object to be literal, not URI resource 83 | rdf_add(rdf, 84 | "https://orcid.org/0000-0002-1642-628X", 85 | "http://schema.org/homepage", 86 | "http://carlboettiger.info", 87 | objectType = "literal") 88 | 89 | 90 | } 91 | \references{ 92 | \url{https://en.wikipedia.org/wiki/Uniform_Resource_Identifier} 93 | } 94 | -------------------------------------------------------------------------------- /man/rdf_free.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rdf_free.R 3 | \name{rdf_free} 4 | \alias{rdf_free} 5 | \title{Free Memory Associated with RDF object} 6 | \usage{ 7 | rdf_free(rdf, rm = TRUE) 8 | } 9 | \arguments{ 10 | \item{rdf}{an rdf object} 11 | 12 | \item{rm}{logical, default TRUE. Remove pointer from parent.frame()? 13 | Usually a good idea since referring to a pointer after it has been 14 | removed can crash R.} 15 | } 16 | \description{ 17 | Free Memory Associated with RDF object 18 | } 19 | \details{ 20 | Free all pointers associated with an rdf object. 21 | Frees memory associated with the storage, world, and model 22 | objects. 23 | } 24 | \examples{ 25 | rdf <- rdf() 26 | rdf_free(rdf) 27 | rm(rdf) 28 | } 29 | -------------------------------------------------------------------------------- /man/rdf_has_bdb.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rdf_has_bdb.R 3 | \name{rdf_has_bdb} 4 | \alias{rdf_has_bdb} 5 | \title{Check for BDB support} 6 | \usage{ 7 | rdf_has_bdb() 8 | } 9 | \value{ 10 | TRUE if BDB support is detected, false otherwise 11 | } 12 | \description{ 13 | Detect whether Berkeley Database for disk-based storage of RDF graphs 14 | is available. Disk-based storage requires redland package 15 | to be installed from source with support for the Berkeley DB 16 | (libdb-dev on Ubuntu, berkeley-db on homebrew), otherwise \code{rdf()} will 17 | fall back to in-memory storage with a warning. 18 | } 19 | \examples{ 20 | rdf_has_bdb() 21 | } 22 | -------------------------------------------------------------------------------- /man/rdf_parse.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rdf_parse.R 3 | \name{rdf_parse} 4 | \alias{rdf_parse} 5 | \title{Parse RDF Files} 6 | \usage{ 7 | rdf_parse( 8 | doc, 9 | format = c("guess", "rdfxml", "nquads", "ntriples", "turtle", "jsonld"), 10 | rdf = NULL, 11 | base = getOption("rdf_base_uri", "localhost://"), 12 | ... 13 | ) 14 | } 15 | \arguments{ 16 | \item{doc}{path, URL, or literal string of the rdf document to parse} 17 | 18 | \item{format}{rdf serialization format of the doc, 19 | one of "rdfxml", "nquads", "ntriples", "turtle" 20 | or "jsonld". If not provided, will try to guess based 21 | on file extension and fall back on rdfxml.} 22 | 23 | \item{rdf}{an existing rdf triplestore to extend with triples from 24 | the parsed file. Default will create a new rdf object.} 25 | 26 | \item{base}{the base URI to assume for any relative URIs (blank nodes)} 27 | 28 | \item{...}{additional parameters (not implemented)} 29 | } 30 | \value{ 31 | an rdf object, containing the redland world 32 | and model objects 33 | } 34 | \description{ 35 | Parse RDF Files 36 | } 37 | \examples{ 38 | doc <- system.file("extdata", "dc.rdf", package="redland") 39 | rdf <- rdf_parse(doc) 40 | 41 | } 42 | -------------------------------------------------------------------------------- /man/rdf_query.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rdf_query.R 3 | \name{rdf_query} 4 | \alias{rdf_query} 5 | \title{Perform a SPARQL Query} 6 | \usage{ 7 | rdf_query(rdf, query, data.frame = TRUE, ...) 8 | } 9 | \arguments{ 10 | \item{rdf}{an rdf object (e.g. from \code{\link{rdf_parse}})} 11 | 12 | \item{query}{a SPARQL query, as text string} 13 | 14 | \item{data.frame}{logical, should the results be returned as a data.frame?} 15 | 16 | \item{...}{additional arguments to a redland initialize-Query} 17 | } 18 | \value{ 19 | a data.frame of all query results (default.) Columns will 20 | be named according to variable names in the SPARQL query. Returned 21 | object values will be coerced to match the corresponding R type 22 | to any associated datatype URI, if provided. If a column would 23 | result in mixed classes (e.g. strings and numerics), all types 24 | in the column will be coerced to character strings. If \code{data.frame} 25 | is false, results will be returned as a list with each element 26 | typed by its data URI. 27 | } 28 | \description{ 29 | Perform a SPARQL Query 30 | } 31 | \examples{ 32 | doc <- system.file("extdata", "dc.rdf", package="redland") 33 | 34 | sparql <- 35 | 'PREFIX dc: 36 | SELECT ?a ?c 37 | WHERE { ?a dc:creator ?c . }' 38 | 39 | rdf <- rdf_parse(doc) 40 | rdf_query(rdf, sparql) 41 | 42 | } 43 | -------------------------------------------------------------------------------- /man/rdf_serialize.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rdf_serialize.R 3 | \name{rdf_serialize} 4 | \alias{rdf_serialize} 5 | \title{Serialize an RDF Document} 6 | \usage{ 7 | rdf_serialize( 8 | rdf, 9 | doc = NULL, 10 | format = c("guess", "rdfxml", "nquads", "ntriples", "turtle", "jsonld"), 11 | namespace = NULL, 12 | prefix = names(namespace), 13 | base = getOption("rdf_base_uri", "localhost://"), 14 | ... 15 | ) 16 | } 17 | \arguments{ 18 | \item{rdf}{an existing rdf triplestore to extend with triples from 19 | the parsed file. Default will create a new rdf object.} 20 | 21 | \item{doc}{file path to write out to. If null, will write to character.} 22 | 23 | \item{format}{rdf serialization format of the doc, 24 | one of "rdfxml", "nquads", "ntriples", "turtle" 25 | or "jsonld". If not provided, will try to guess based 26 | on file extension and fall back on rdfxml.} 27 | 28 | \item{namespace}{a named character containing the prefix to namespace bindings. \code{names(namespace)} are the prefixes, whereas \code{namespace} are the namespaces} 29 | 30 | \item{prefix}{(optional) for backward compatibility. See \code{namespace}. It contains the matching prefixes to the namespaces in \code{namespace} and is set automatically if you provide \code{namespace} as a named character vector.} 31 | 32 | \item{base}{the base URI to assume for any relative URIs (blank nodes)} 33 | 34 | \item{...}{additional arguments to \code{redland::serializeToFile}} 35 | } 36 | \value{ 37 | rdf_serialize returns the output file path \code{doc} invisibly. 38 | This makes it easier to use rdf_serialize in pipe chains with 39 | \code{\link{rdf_parse}}. 40 | } 41 | \description{ 42 | Serialize an RDF Document 43 | } 44 | \examples{ 45 | infile <- system.file("extdata", "dc.rdf", package="redland") 46 | out <- tempfile("file", fileext = ".rdf") 47 | 48 | some_rdf <- rdf_parse(infile) 49 | rdf_add(some_rdf, 50 | subject = "http://www.dajobe.org/dave-beckett", 51 | predicate = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", 52 | object = "http://xmlns.com/foaf/0.1/Person") 53 | rdf_serialize(some_rdf, out) 54 | 55 | ## With a namespace 56 | rdf_serialize(some_rdf, 57 | out, 58 | format = "turtle", 59 | namespace = c(dc = "http://purl.org/dc/elements/1.1/", 60 | foaf = "http://xmlns.com/foaf/0.1/") 61 | ) 62 | 63 | readLines(out) 64 | } 65 | -------------------------------------------------------------------------------- /man/rdflib-package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rdf.R 3 | \docType{package} 4 | \name{rdflib-package} 5 | \alias{rdflib} 6 | \alias{rdflib-package} 7 | \title{rdflib: Tools to Manipulate and Query Semantic Data} 8 | \description{ 9 | The Resource Description Framework, or RDF is a widely used 10 | data representation model that forms the cornerstone of the 11 | Semantic Web. 'RDF' represents data as a graph rather than 12 | the familiar data table or rectangle of relational databases. 13 | } 14 | \details{ 15 | It has three main goals: 16 | 17 | \itemize{ 18 | \item Easily read, write, and convert between all major RDF serialization formats 19 | \item Support SPARQL queries to extract data from an RDF graph into a data.frame 20 | \item Support JSON-LD format as a first-class citizen in RDF manipulations 21 | } 22 | 23 | For more information, see the Wikipedia pages for RDF, SPARQL, and JSON-LD: 24 | 25 | \itemize{ 26 | \item \url{https://en.wikipedia.org/wiki/Resource_Description_Framework} 27 | \item \url{https://en.wikipedia.org/wiki/SPARQL} 28 | \item \url{https://en.wikipedia.org/wiki/JSON-LD} 29 | } 30 | 31 | To learn more about rdflib, start with the vignettes: 32 | \code{browseVignettes(package = "rdflib")} 33 | 34 | Configurations via \code{options()} 35 | 36 | \code{rdf_print_format}: 37 | \itemize{ 38 | \item NULL or "nquads" (default) 39 | \item any valid serializer name: e.g. "rdfxml", "jsonld", "turtle", "ntriples" 40 | } 41 | 42 | \code{rdf_base_uri}: 43 | \itemize{ 44 | \item Default base URI to use (when serializing JSON-LD only at this time) 45 | default is "localhost://" 46 | } 47 | 48 | \code{rdf_max_print}: 49 | \itemize{ 50 | \item maximum number of lines to print from rdf, default 10 51 | } 52 | } 53 | \seealso{ 54 | Useful links: 55 | \itemize{ 56 | \item \url{https://github.com/ropensci/rdflib} 57 | \item Report bugs at \url{https://github.com/ropensci/rdflib/issues} 58 | } 59 | 60 | } 61 | \author{ 62 | \strong{Maintainer}: Carl Boettiger \email{cboettig@gmail.com} (\href{https://orcid.org/0000-0002-1642-628X}{ORCID}) [copyright holder] 63 | 64 | Other contributors: 65 | \itemize{ 66 | \item Bryce Mecum (\href{https://orcid.org/0000-0002-0381-3766}{ORCID}) [reviewer] 67 | \item Anna Krystalli (\href{https://orcid.org/0000-0002-2378-4915}{ORCID}) [reviewer] 68 | \item Viktor Senderov \email{vsenderov@gmail.com} (\href{https://orcid.org/0000-0003-3340-5963}{ORCID}) [contributor] 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /man/read_nquads.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/write_nquads.R 3 | \name{read_nquads} 4 | \alias{read_nquads} 5 | \title{read an nquads file} 6 | \usage{ 7 | read_nquads(file, ...) 8 | } 9 | \arguments{ 10 | \item{file}{path to nquads file} 11 | 12 | \item{...}{additional arguments to \code{\link[=rdf_parse]{rdf_parse()}}} 13 | } 14 | \value{ 15 | an rdf object. See \code{\link[=rdf_parse]{rdf_parse()}} 16 | } 17 | \description{ 18 | read an nquads file 19 | } 20 | \examples{ 21 | tmp <- tempfile(fileext = ".nq") 22 | library(datasets) 23 | write_nquads(iris, tmp) 24 | read_nquads(tmp) 25 | 26 | } 27 | -------------------------------------------------------------------------------- /man/write_nquads.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/write_nquads.R 3 | \name{write_nquads} 4 | \alias{write_nquads} 5 | \title{write object out as nquads} 6 | \usage{ 7 | write_nquads(x, file, ...) 8 | } 9 | \arguments{ 10 | \item{x}{an object that can be represented as nquads} 11 | 12 | \item{file}{output filename} 13 | 14 | \item{...}{additional parameters, see examples} 15 | } 16 | \description{ 17 | write object out as nquads 18 | } 19 | \examples{ 20 | tmp <- tempfile(fileext = ".nq") 21 | library(datasets) 22 | 23 | ## convert data.frame to nquads 24 | write_nquads(iris, tmp) 25 | rdf <- read_nquads(tmp) 26 | 27 | ## or starting a native rdf object 28 | write_nquads(rdf, tempfile(fileext = ".nq")) 29 | } 30 | -------------------------------------------------------------------------------- /manuscripts/rdflib/RJreferences.bib: -------------------------------------------------------------------------------- 1 | @Manual{R, 2 | title = {R: A Language and Environment for Statistical Computing}, 3 | author = {{R Core Team}}, 4 | organization = {R Foundation for Statistical Computing}, 5 | address = {Vienna, Austria}, 6 | year = {2012}, 7 | note = {{ISBN} 3-900051-07-0}, 8 | url = {http://www.R-project.org/}, 9 | } 10 | 11 | @article{ihaka:1996, 12 | Author = {Ihaka, Ross and Gentleman, Robert}, 13 | Journal = {Journal of Computational and Graphical Statistics}, 14 | Number = 3, 15 | Pages = {299--314}, 16 | Title = {R: A Language for Data Analysis and Graphics}, 17 | Volume = 5, 18 | Year = 1996} 19 | 20 | 21 | @article{Ross2017, 22 | author = {Ross, Zev and Wickham, Hadley and Robinson, David}, 23 | doi = {10.7287/peerj.preprints.3180v1}, 24 | issn = {2167-9843}, 25 | journal = {PeerJ Preprints}, 26 | pages = {e3180v1}, 27 | title = {{Declutter your R workflow with tidy tools}}, 28 | url = {https://doi.org/10.7287/peerj.preprints.3180v1}, 29 | volume = {5}, 30 | year = {2017} 31 | } 32 | 33 | -------------------------------------------------------------------------------- /manuscripts/rdflib/Rlogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/manuscripts/rdflib/Rlogo.png -------------------------------------------------------------------------------- /manuscripts/rdflib/preamble.tex: -------------------------------------------------------------------------------- 1 | % Any extra LaTeX you need in the preamble 2 | -------------------------------------------------------------------------------- /paper.bib: -------------------------------------------------------------------------------- 1 | 2 | 3 | @MISC{W3C_jsonld, 4 | url = {https://www.w3.org/TR/json-ld/}, 5 | author = {Manu Sporny and Dave Longley and Gregg Kellogg and Markus Lanthaler and Niklas Lindström}, 6 | canonicaluri = {\url{https://www.w3.org/TR/json-ld/}}, 7 | title = {{JSON-LD 1.0: A JSON-based Serialization for Linked Data}}, 8 | YEAR = {2017} 9 | } 10 | 11 | 12 | @MISC{W3C_RDF, 13 | url = {https://www.w3.org/TR/rdf11-primer/}, 14 | author = {Guss Schreiber and Yves Raimond}, 15 | title = {{RDF 1.1 Primer}}, 16 | YEAR = {2014}, 17 | } 18 | 19 | 20 | @MISC{W3C_SPARQL, 21 | url = {https://www.w3.org/TR/rdf-sparql-query/}, 22 | author = {Eric Prud'hommeaux and Andy Seaborne}, 23 | title = {{SPARQL Query Language for RDF}}, 24 | YEAR = {2008}, 25 | } 26 | 27 | 28 | @MISC{SPARQL, 29 | url = {https://en.wikipedia.org/wiki/SPARQL}, 30 | author = {Wikipedia}, 31 | title = {SPARQL}, 32 | YEAR = {2017}, 33 | } 34 | @MISC{RDF, 35 | url = {https://en.wikipedia.org/wiki/Resource_Description_Framework}, 36 | author = {Wikipedia}, 37 | title = {{Resource Description Framework}}, 38 | YEAR = {2017}, 39 | } 40 | 41 | https://en.wikipedia.org/wiki/Resource_Description_Framework 42 | 43 | @Manual{jsonld, 44 | title = {{jsonld: JSON for Linking Data}}, 45 | author = {Jeroen Ooms}, 46 | year = {2017}, 47 | note = {R package version 1.2}, 48 | url = {https://CRAN.R-project.org/package=jsonld}, 49 | } 50 | 51 | @Manual{redland, 52 | title = {{redland: RDF Library Bindings in R}}, 53 | author = {Matthew B. Jones and Peter Slaughter and Jeroen Ooms and Carl Boettiger and Scott Chamberlain}, 54 | year = {2016}, 55 | note = {R package version 1.0.17-9}, 56 | url = {https://github.com/ropensci/redland-bindings/tree/master/R/redland}, 57 | doi = {10.5063/F1VM496B}, 58 | } -------------------------------------------------------------------------------- /paper.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Tools to Manipulate and Query Semantic Data' 3 | tags: 4 | - linked data 5 | - rdf 6 | - sparql 7 | - semantic 8 | - json-ld 9 | authors: 10 | - name: Carl Boettiger 11 | orcid: 0000-0002-1642-628X 12 | affiliation: 1 13 | affiliations: 14 | - name: University of California, Berkeley 15 | index: 1 16 | date: 2017-12-11 17 | bibliography: paper.bib 18 | --- 19 | 20 | # Summary 21 | 22 | The Resource Description Framework, or RDF [@RDF; @W3C_RDF] is a widely used 23 | data representation model that forms the cornerstone of the 24 | Semantic Web. RDF represents data as a graph rather than 25 | the familiar data table or rectangle of relational databases. 26 | The `rdflib` package provides a friendly and concise user interface 27 | for performing common tasks on RDF data, such as reading, writing 28 | and converting between the various serializations of RDF data, 29 | including `rdfxml`, `turtle`, `nquads`, `ntriples`, and `json-ld`; 30 | creating new `rdf` graphs, and performing graph queries using SPARQL [@SPARQL; @W3C_SPARQL]. 31 | This package wraps the low level `redland` R package [@redland] which 32 | provides direct bindings to the redland C library. Additionally, 33 | the package supports the newer and more developer friendly 34 | JSON-LD format through the `jsonld` package [@jsonld; @W3C_jsonld]. 35 | 36 | # References 37 | -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/pkgdown/favicon/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/pkgdown/favicon/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/pkgdown/favicon/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/pkgdown/favicon/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/pkgdown/favicon/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/pkgdown/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/pkgdown/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/pkgdown/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/pkgdown/favicon/favicon.ico -------------------------------------------------------------------------------- /precompute-storage-vignette.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo ' 3 | Sys.sleep(5) 4 | system("virtuoso-t -c /etc/virtuoso-opensource-6.1/virtuoso.ini") 5 | Sys.sleep(5) 6 | knitr::knit("vignettes/articles/storage.Rmd.orig", output = "vignettes/articles/storage.Rmd")' > precompute.R 7 | 8 | 9 | docker-compose run rdflib R -f precompute.R 10 | rm precompute.R 11 | -------------------------------------------------------------------------------- /rdflib.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: knitr 13 | LaTeX: pdfLaTeX 14 | 15 | BuildType: Package 16 | PackageUseDevtools: Yes 17 | PackageInstallArgs: --no-multiarch --with-keep.source 18 | PackageRoxygenize: rd,collate,namespace 19 | -------------------------------------------------------------------------------- /slides/img/codemeta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/slides/img/codemeta.png -------------------------------------------------------------------------------- /slides/img/data-growth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/slides/img/data-growth.png -------------------------------------------------------------------------------- /slides/img/data-janitor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/slides/img/data-janitor.jpg -------------------------------------------------------------------------------- /slides/img/data-lake.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/slides/img/data-lake.jpg -------------------------------------------------------------------------------- /slides/img/data-workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/slides/img/data-workflow.png -------------------------------------------------------------------------------- /slides/img/factory-farm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/slides/img/factory-farm.jpg -------------------------------------------------------------------------------- /slides/img/field-notes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/slides/img/field-notes.jpg -------------------------------------------------------------------------------- /slides/img/integration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/slides/img/integration.png -------------------------------------------------------------------------------- /slides/img/landsat2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/slides/img/landsat2.jpg -------------------------------------------------------------------------------- /slides/img/neon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/slides/img/neon.png -------------------------------------------------------------------------------- /slides/img/no-data-lake-scaled.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/slides/img/no-data-lake-scaled.jpg -------------------------------------------------------------------------------- /slides/img/no-data-lake.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/slides/img/no-data-lake.jpg -------------------------------------------------------------------------------- /slides/img/organic-farm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/slides/img/organic-farm.png -------------------------------------------------------------------------------- /slides/img/semantics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/slides/img/semantics.png -------------------------------------------------------------------------------- /slides/img/steampunk-phone.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/slides/img/steampunk-phone.jpg -------------------------------------------------------------------------------- /slides/img/steampunk.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/slides/img/steampunk.jpg -------------------------------------------------------------------------------- /slides/img/tetris-lose.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/slides/img/tetris-lose.jpg -------------------------------------------------------------------------------- /slides/img/tetris.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/rdflib/c2b3f3a5c28648e3f87c1ccb2e2e49bebd082e2d/slides/img/tetris.jpg -------------------------------------------------------------------------------- /slides/libs/remark-css/default-fonts.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Yanone+Kaffeesatz); 2 | @import url(https://fonts.googleapis.com/css?family=Droid+Serif:400,700,400italic); 3 | @import url(https://fonts.googleapis.com/css?family=Source+Code+Pro:400,700); 4 | 5 | body { font-family: 'Droid Serif', 'Palatino Linotype', 'Book Antiqua', Palatino, 'Microsoft YaHei', 'Songti SC', serif; } 6 | h1, h2, h3 { 7 | font-family: 'Yanone Kaffeesatz'; 8 | font-weight: normal; 9 | } 10 | .remark-code, .remark-inline-code { font-family: 'Source Code Pro', 'Lucida Console', Monaco, monospace; } 11 | -------------------------------------------------------------------------------- /slides/libs/remark-css/default.css: -------------------------------------------------------------------------------- 1 | a, a > code { 2 | color: rgb(249, 38, 114); 3 | text-decoration: none; 4 | } 5 | .footnote { 6 | position: absolute; 7 | bottom: 3em; 8 | padding-right: 4em; 9 | font-size: 90%; 10 | } 11 | .remark-code-line-highlighted { background-color: #ffff88; } 12 | 13 | .inverse { 14 | background-color: #272822; 15 | color: #d6d6d6; 16 | text-shadow: 0 0 20px #333; 17 | } 18 | .inverse h1, .inverse h2, .inverse h3 { 19 | color: #f3f3f3; 20 | } 21 | /* Two-column layout */ 22 | .left-column { 23 | color: #777; 24 | width: 20%; 25 | height: 92%; 26 | float: left; 27 | } 28 | .left-column h2:last-of-type, .left-column h3:last-child { 29 | color: #000; 30 | } 31 | .right-column { 32 | width: 75%; 33 | float: right; 34 | padding-top: 1em; 35 | } 36 | .pull-left { 37 | float: left; 38 | width: 47%; 39 | } 40 | .pull-right { 41 | float: right; 42 | width: 47%; 43 | } 44 | .pull-right ~ * { 45 | clear: both; 46 | } 47 | img, video, iframe { 48 | max-width: 100%; 49 | } 50 | blockquote { 51 | border-left: solid 5px lightgray; 52 | padding-left: 1em; 53 | } 54 | table { 55 | margin: auto; 56 | border-top: 1px solid #666; 57 | border-bottom: 1px solid #666; 58 | } 59 | table thead th { border-bottom: 1px solid #ddd; } 60 | th, td { padding: 5px; } 61 | thead, tfoot, tr:nth-child(even) { background: #eee } 62 | 63 | @page { margin: 0; } 64 | @media print { 65 | .remark-slide-scaler { 66 | width: 100% !important; 67 | height: 100% !important; 68 | transform: scale(1) !important; 69 | top: 0 !important; 70 | left: 0 !important; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tests/spelling.R: -------------------------------------------------------------------------------- 1 | if(requireNamespace('spelling', quietly=TRUE)) 2 | spelling::spell_check_test(vignettes = TRUE, error = FALSE, skip_on_cran = TRUE) 3 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(rdflib) 3 | 4 | test_check("rdflib") 5 | -------------------------------------------------------------------------------- /tests/testthat/test-as_rdf.R: -------------------------------------------------------------------------------- 1 | testthat::context("as_rdf") 2 | 3 | ## tests coming, see vignettes 4 | 5 | -------------------------------------------------------------------------------- /tests/testthat/test-parse-serialize.R: -------------------------------------------------------------------------------- 1 | testthat::context("Parsers and Serializers") 2 | 3 | doc <- system.file("extdata/example.rdf", package="redland") 4 | out <- "testing.rdf" 5 | 6 | 7 | 8 | testthat::test_that("we can serialize to character", { 9 | rdf <- rdf_parse(doc) 10 | txt <- rdf_serialize(rdf, format = "nquads") 11 | testthat::expect_is(txt, "character") 12 | testthat::expect_match(txt, "John Smith") 13 | rdf_free(rdf) 14 | }) 15 | 16 | 17 | testthat::test_that("we can parse (in rdfxml) 18 | and serialize (in nquads) a simple rdf graph", { 19 | rdf <- rdf_parse(doc) 20 | rdf_serialize(rdf, out, "nquads") 21 | roundtrip <- rdf_parse(out, "nquads") 22 | testthat::expect_is(roundtrip, "rdf") 23 | 24 | rdf_free(roundtrip) 25 | rdf_free(rdf) 26 | }) 27 | 28 | testthat::test_that("we can add a namespace on serializing", { 29 | rdf <- rdf_parse(doc) 30 | rdf_serialize(rdf, 31 | out, 32 | namespace = "http://purl.org/dc/elements/1.1/", 33 | prefix = "dc") 34 | roundtrip <- rdf_parse(doc) 35 | testthat::expect_is(roundtrip, "rdf") 36 | 37 | rdf_free(rdf) 38 | rdf_free(roundtrip) 39 | 40 | }) 41 | 42 | ################################################################ 43 | 44 | 45 | testthat::test_that("we can parse and serialize json-ld", { 46 | 47 | skip_if_not_installed("jsonld") 48 | skip_on_cran() # JSON-LD uses internet resources 49 | 50 | rdf <- rdf_parse(doc) 51 | rdf_serialize(rdf, "out.json") 52 | roundtrip <- rdf_parse("out.json") 53 | testthat::expect_is(roundtrip, "rdf") 54 | rdf_serialize(rdf, "out.jsonld") 55 | unlink("out.json") 56 | unlink("out.jsonld") 57 | rdf_free(roundtrip) 58 | rdf_free(rdf) 59 | 60 | }) 61 | 62 | testthat::test_that("we can parse and serialize nquads", { 63 | rdf <- rdf_parse(doc) 64 | rdf_serialize(rdf, "out.nquads") 65 | roundtrip <- rdf_parse("out.nquads") 66 | testthat::expect_is(roundtrip, "rdf") 67 | unlink("nquads") 68 | rdf_free(roundtrip) 69 | rdf_free(rdf) 70 | 71 | }) 72 | testthat::test_that("we can parse and serialize ntriples", { 73 | rdf <- rdf_parse(doc) 74 | rdf_serialize(rdf, "out.nt") 75 | roundtrip <- rdf_parse("out.nt") 76 | testthat::expect_is(roundtrip, "rdf") 77 | unlink("out.nt") 78 | rdf_serialize(rdf, "out.ntriples") 79 | unlink("out.ntriples") 80 | 81 | rdf_free(roundtrip) 82 | rdf_free(rdf) 83 | }) 84 | testthat::test_that("we can parse and serialize tutle", { 85 | rdf <- rdf_parse(doc) 86 | rdf_serialize(rdf, "out.ttl") 87 | roundtrip <- rdf_parse("out.ttl") 88 | testthat::expect_is(roundtrip, "rdf") 89 | unlink("out.ttl") 90 | rdf_serialize(rdf, "out.turtle") 91 | unlink("out.turtle") 92 | 93 | rdf_free(roundtrip) 94 | rdf_free(rdf) 95 | }) 96 | testthat::test_that("we can parse and serialize rdfxml", { 97 | rdf <- rdf_parse(doc) 98 | rdf_serialize(rdf, "out.rdf") 99 | roundtrip <- rdf_parse("out.rdf") 100 | testthat::expect_is(roundtrip, "rdf") 101 | 102 | unlink("out.rdf") 103 | rdf_serialize(rdf, "out.xml") 104 | unlink("out.xml") 105 | 106 | rdf_free(roundtrip) 107 | rdf_free(rdf) 108 | }) 109 | 110 | ################################################################ 111 | 112 | 113 | testthat::test_that("we can parse by guessing on the file extension", { 114 | 115 | 116 | 117 | ex <- system.file("extdata/person.nq", package="rdflib") 118 | rdf <- rdf_parse(ex) 119 | rdf_serialize(rdf, "tmp.nq", base = "http://schema.org/") 120 | roundtrip <- rdf_parse("tmp.nq", "turtle") 121 | testthat::expect_is(roundtrip, "rdf") 122 | unlink("tmp.nq") 123 | rdf_free(rdf) 124 | }) 125 | 126 | 127 | testthat::test_that("we can serialize turtle with a baseUri", { 128 | ex <- system.file("extdata/person.nq", package="rdflib") 129 | rdf <- rdf_parse(ex, "nquads") 130 | rdf_serialize(rdf, out, "turtle", base = "http://schema.org/") 131 | roundtrip <- rdf_parse(out, "turtle") 132 | testthat::expect_is(roundtrip, "rdf") 133 | rdf_free(rdf) 134 | }) 135 | 136 | 137 | ## JSON-LD tests with default base uri 138 | 139 | testthat::test_that("@id is not a URI, we should get localhost", { 140 | 141 | skip_if_not_installed("jsonld") 142 | skip_on_cran() 143 | 144 | ex <- '{ 145 | "@context": "http://schema.org/", 146 | "@id": "person_id", 147 | "name": "Jane Doe" 148 | }' 149 | 150 | rdf <- rdf_parse(ex, "jsonld") 151 | testthat::expect_output(cat(format(rdf, "nquads")), "localhost") 152 | rdf_free(rdf) 153 | }) 154 | 155 | testthat::test_that("@id is a URI, we should not get localhost", { 156 | 157 | skip_if_not_installed("jsonld") 158 | skip_on_cran() 159 | 160 | ex <- '{ 161 | "@context": "http://schema.org/", 162 | "@id": "uri:person_id", 163 | "name": "Jane Doe" 164 | }' 165 | rdf <- rdf_parse(ex, "jsonld") 166 | testthat::expect_false(grepl("localhost", format(rdf, "nquads"))) 167 | rdf_free(rdf) 168 | }) 169 | 170 | testthat::test_that("we can alter the base URI", { 171 | 172 | skip_if_not_installed("jsonld") 173 | skip_on_cran() 174 | 175 | 176 | ex <- '{ 177 | "@id": "person_id", 178 | "schema:name": "Jane Doe" 179 | }' 180 | options(rdf_base_uri = "http://example.com/") 181 | rdf <- rdf_parse(ex, "jsonld") 182 | testthat::expect_output(cat(format(rdf, "nquads")), "http://example.com") 183 | rdf_free(rdf) 184 | 185 | 186 | options(rdf_base_uri = "") 187 | rdf <- rdf_parse(ex, "jsonld") 188 | testthat::expect_length(rdf, 0) 189 | rdf_free(rdf) 190 | 191 | options(rdf_base_uri = NULL) 192 | }) 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | testthat::test_that("we can parse into an existing rdf model", { 201 | rdf1 <- rdf_parse(system.file("extdata/ex.xml", package = "rdflib")) 202 | rdf2 <- rdf_parse(system.file("extdata/ex2.xml", package = "rdflib"), 203 | rdf = rdf1) 204 | 205 | testthat::expect_is(rdf1, "rdf") 206 | testthat::expect_is(rdf2, "rdf") 207 | testthat::expect_identical(rdf1, rdf2) 208 | rdf_free(rdf1) 209 | 210 | ## NOTE: rdf is same pointer as rdf1, not a new pointer. cannot free twice 211 | }) 212 | 213 | 214 | 215 | testthat::test_that("we can parse from a url", { 216 | 217 | testthat::skip_on_cran() 218 | rdf <- rdf_parse("https://tinyurl.com/ycf95c9h") 219 | testthat::expect_is(rdf, "rdf") 220 | 221 | rdf_free(rdf) 222 | }) 223 | 224 | testthat::test_that("we can parse from a text string", { 225 | 226 | 227 | rdf <- rdf_parse(doc) 228 | txt <- rdf_serialize(rdf, format = "rdfxml") 229 | testthat::expect_is(txt, "character") 230 | roundtrip <- rdf_parse(txt, format="rdfxml") 231 | testthat::expect_is(roundtrip, "rdf") 232 | rdf_free(rdf) 233 | 234 | string <- 235 | ' 236 | _:b0 "Professor" . 237 | _:b0 "Jane Doe" . 238 | _:b0 "35" . 239 | _:b0 . 240 | ' 241 | rdf <- rdf_parse(string, "nquads") 242 | testthat::expect_is(rdf, "rdf") 243 | 244 | rdf_free(rdf) 245 | }) 246 | 247 | unlink(out) 248 | 249 | -------------------------------------------------------------------------------- /tests/testthat/test-rdf.R: -------------------------------------------------------------------------------- 1 | testthat::context("test-rdf.R") 2 | 3 | doc <- system.file("extdata/example.rdf", package="redland") 4 | out <- "testing.rdf" 5 | 6 | 7 | testthat::test_that("We can initialize and free rdf objects", { 8 | rdf <- rdf() 9 | 10 | testthat::expect_is(rdf, "rdf") 11 | testthat::expect_is(rdf$world, "World") 12 | testthat::expect_is(rdf$model, "Model") 13 | testthat::expect_is(rdf$storage, "Storage") 14 | 15 | rdf_free(rdf) 16 | 17 | ## Confirm `rdf` has been removed from the workspace 18 | testthat::expect_false("rdf" %in% ls()) 19 | 20 | RDF_graph <- rdf() 21 | testthat::expect_true("RDF_graph" %in% ls()) 22 | rdf_free(RDF_graph) 23 | testthat::expect_false("RDF_graph" %in% ls()) 24 | }) 25 | 26 | testthat::test_that("we can concatenate rdfs", { 27 | rdf1 <- rdf_parse(system.file("extdata/ex.xml", package = "rdflib")) 28 | rdf2 <- rdf_parse(system.file("extdata/ex2.xml", package = "rdflib")) 29 | rdf <- c(rdf1, rdf2) 30 | testthat::expect_is(rdf, "rdf") 31 | 32 | rdf_free(rdf1) 33 | rdf_free(rdf2) 34 | ## NOTE: rdf is same pointer as rdf1, not a new pointer. cannot free twice 35 | }) 36 | 37 | 38 | 39 | testthat::test_that("we can add, parse and serialize json-ld", { 40 | 41 | skip_if_not_installed("jsonld") 42 | skip_on_cran() 43 | 44 | x <- rdf() 45 | x <- rdf_add(x, 46 | subject="http://www.dajobe.org/", 47 | predicate="http://purl.org/dc/elements/1.1/language", 48 | object="en") 49 | rdf_serialize(x, out, "jsonld") 50 | rdf <- rdf_parse(out, format = "jsonld") 51 | testthat::expect_is(rdf, "rdf") 52 | rdf_free(x) 53 | rdf_free(rdf) 54 | 55 | }) 56 | 57 | 58 | 59 | 60 | testthat::test_that("print and format work", { 61 | rdf <- rdf_parse(doc) 62 | txt <- format(rdf, format = "rdfxml") 63 | testthat::expect_output(print(rdf), ".*johnsmith.*") 64 | 65 | testthat::expect_is(txt, "character") 66 | rdf_free(rdf) 67 | }) 68 | 69 | 70 | 71 | 72 | 73 | 74 | unlink(out) 75 | 76 | -------------------------------------------------------------------------------- /tests/testthat/test-rdf_add.R: -------------------------------------------------------------------------------- 1 | context("RDF Add") 2 | 3 | test_that("we can print.rdf UTF-8", { 4 | # stringi::stri_unescape_unicode fails on some architectures 5 | skip_on_cran() 6 | skip_on_os("windows") 7 | r <- rdf() 8 | rdf_add(r, 9 | subject="", 10 | predicate="http://schema.org/name", 11 | object="Maëlle Salmon") 12 | 13 | expect_output(print(r), "Maëlle") 14 | rdf_free(r) 15 | }) 16 | 17 | 18 | 19 | test_that("we can initialize add triples to rdf graph", { 20 | rdf <- rdf() 21 | rdf <- rdf_add(rdf, 22 | subject="http://www.dajobe.org/", 23 | predicate="http://schema.org/dateCreated", 24 | object=as.Date("2015-01-01")) 25 | expect_is(rdf, "rdf") 26 | rdf_free(rdf) 27 | 28 | }) 29 | 30 | 31 | test_that("we can initialize add triples to rdf graph", { 32 | rdf <- rdf() 33 | rdf <- rdf_add(rdf, 34 | subject=NA, 35 | predicate="http://schema.org/dateCreated", 36 | object=NA) 37 | expect_is(rdf, "rdf") 38 | rdf_free(rdf) 39 | 40 | }) 41 | 42 | test_that("other rdf_add examples work",{ 43 | 44 | rdf <- rdf() 45 | rdf_add(rdf, 46 | subject="http://www.dajobe.org/", 47 | predicate="http://purl.org/dc/elements/1.1/language", 48 | object="en") 49 | 50 | ## non-URI string in subject indicates a blank subject 51 | ## (prefixes to "_:b0") 52 | rdf_add(rdf, "b0", "http://schema.org/jobTitle", "Professor") 53 | 54 | ## identically a blank subject. 55 | ## Note rdf is unchanged when we add the same triple twice. 56 | rdf_add(rdf, "b0", "http://schema.org/jobTitle", "Professor", 57 | subjectType = "blank") 58 | 59 | ## blank node with empty string creates a default blank node id 60 | rdf_add(rdf, "", "http://schema.org/jobTitle", "Professor") 61 | 62 | 63 | ## Subject and Object both recognized as URI resources: 64 | rdf_add(rdf, 65 | "https://orcid.org/0000-0002-1642-628X", 66 | "http://schema.org/homepage", 67 | "http://carlboettiger.info") 68 | 69 | ## Force object to be literal, not URI resource 70 | rdf_add(rdf, 71 | "https://orcid.org/0000-0002-1642-628X", 72 | "http://schema.org/homepage", 73 | "http://carlboettiger.info", 74 | objectType = "literal") 75 | 76 | 77 | expect_is(rdf, "rdf") 78 | rdf_free(rdf) 79 | }) 80 | -------------------------------------------------------------------------------- /tests/testthat/test-rdf_query.R: -------------------------------------------------------------------------------- 1 | testthat::context("SPARQL Queries") 2 | 3 | doc <- system.file("extdata/example.rdf", package="redland") 4 | out <- "testing.rdf" 5 | 6 | testthat::test_that("we can make CONSTRUCT queries", { 7 | 8 | testthat::skip("No test for SPARQL CONSTRUCT") 9 | 10 | ## No errors but no return either, not sure 11 | ## what the correct construction is. 12 | ## currently registers as a skipped test. 13 | rdf <- rdf() 14 | rdf_add(rdf, 15 | "http://carlboettiger.info", 16 | "http://schema.org/name", 17 | "Carl Boettiger") 18 | sparql <- 'CONSTRUCT { ?x ?p ?o . } 19 | WHERE { ?x ?p ?o . }' 20 | 21 | rdf_query(rdf, sparql, data.frame = FALSE) 22 | 23 | 24 | rdf_free(rdf) 25 | 26 | }) 27 | 28 | testthat::test_that("we can make sparql queries", { 29 | sparql <- 30 | 'PREFIX dc: 31 | SELECT ?a ?c 32 | WHERE { ?a dc:creator ?c . }' 33 | 34 | rdf <- rdf_parse(doc) 35 | match <- rdf_query(rdf, sparql) 36 | testthat::expect_length(match, 2) 37 | 38 | rdf_free(rdf) 39 | 40 | }) 41 | 42 | testthat::test_that("SPARQL handles data types", { 43 | 44 | rdf <- rdf() 45 | rdf_add(rdf, "", "ex:integer", 33L) 46 | rdf_add(rdf, "", "ex:decimal", 3.141) 47 | rdf_add(rdf, "", "ex:decimal", 2.718) 48 | rdf_add(rdf, "", "ex:logical", TRUE) 49 | rdf_add(rdf, "", "ex:Date", Sys.Date()) 50 | rdf_add(rdf, "", "ex:POSIXct", Sys.time()) 51 | rdf_add(rdf, "", "ex:factor", as.factor("text")) 52 | rdf_add(rdf, "", "ex:string", "text") 53 | 54 | ## Select ?s as well to avoid silly warning 55 | testthat::expect_is(rdf, "rdf") 56 | match <- rdf_query(rdf, 'SELECT ?o ?s WHERE { ?s ?o }') 57 | testthat::expect_type(match$o[[1]], "double") 58 | testthat::expect_is(match$o[[1]], "Date") 59 | 60 | match <- rdf_query(rdf, 'SELECT ?o ?s WHERE { ?s ?o }') 61 | testthat::expect_is(match$o[[1]], "POSIXct") 62 | testthat::expect_type(match$o[[1]], "double") 63 | 64 | match <- rdf_query(rdf, 'SELECT ?o ?s WHERE { ?s ?o }') 65 | testthat::expect_is(match$o[[1]], "numeric") 66 | testthat::expect_type(match$o[[1]], "double") 67 | 68 | ## readr fails to detect "true" as a logical 69 | #match <- rdf_query(rdf, 'SELECT ?o ?s WHERE { ?s ?o }') 70 | #testthat::expect_is(match$o[[1]], "logical") 71 | #testthat::expect_type(match$o[[1]], "logical") 72 | 73 | match <- rdf_query(rdf, 'SELECT ?o ?s WHERE { ?s ?o }') 74 | testthat::expect_is(match$o[[1]], "numeric") 75 | testthat::expect_type(match$o[[1]], "double") 76 | 77 | match <- rdf_query(rdf, 'SELECT ?o ?s WHERE { ?s ?o }') 78 | testthat::expect_is(match$o[[1]], "character") 79 | testthat::expect_type(match$o[[1]], "character") 80 | 81 | 82 | ## Matching mixed type results in all types treated as character 83 | # vector, since o is a single column.... 84 | match <- rdf_query(rdf, 'SELECT ?s ?p ?o WHERE { ?s ?p ?o }') 85 | testthat::expect_is(match$o, "character") 86 | testthat::expect_is(match, "data.frame") 87 | 88 | 89 | rdf_free(rdf) 90 | 91 | }) 92 | 93 | unlink(out) 94 | 95 | 96 | -------------------------------------------------------------------------------- /tests/testthat/test-rdf_storage.R: -------------------------------------------------------------------------------- 1 | testthat::context("RDF Storage") 2 | 3 | testthat::test_that("SQLite Backend", { 4 | testthat::skip_on_cran() 5 | 6 | testthat::skip_if_not(rdf_storage("sqlite", new_db = TRUE, 7 | check_only = TRUE, name = "rdflib.sqlite")) 8 | testthat::expect_silent(r <- rdf(storage="sqlite", 9 | new_db = TRUE, 10 | name="rdflib.sqlite")) 11 | rdf_add(r, "", "dc:name", "bob") 12 | testthat::expect_match(format(r, "nquads"), "bob") 13 | testthat::expect_is(r, "rdf") 14 | rdf_free(r) 15 | unlink("rdflib.sqlite") 16 | 17 | 18 | }) 19 | 20 | testthat::test_that("Postgres Backend", { 21 | testthat::skip_on_travis() 22 | testthat::skip_on_cran() 23 | 24 | testthat::skip_if_not(rdf_storage("postgres", 25 | host="postgres", user="postgres", 26 | password="rdflib", new_db = TRUE, 27 | check_only = TRUE)) 28 | testthat::expect_silent( 29 | rdf <- rdf(storage="postgres", host = "postgres", 30 | user="postgres", password="rdflib", new_db = TRUE) 31 | ) 32 | 33 | rdf_add(rdf, "", "dc:name", "bob") 34 | testthat::expect_match(format(rdf, "nquads"), "bob") 35 | testthat::expect_is(rdf, "rdf") 36 | rdf_free(rdf) 37 | 38 | }) 39 | 40 | 41 | ## Note: `mysql` is the name default database created by mariadb 42 | testthat::test_that("MySQL Backend", { 43 | testthat::skip_on_cran() 44 | testthat::skip_on_travis() 45 | testthat::skip_if_not(rdf_storage("mysql", host = "mariadb", 46 | user="root", password="rdflib", 47 | database = "mysql", 48 | new_db=TRUE, check_only = TRUE )) 49 | testthat::expect_silent( 50 | rdf <- rdf(storage="mysql", host = "mariadb", 51 | user="root", password="rdflib", 52 | database = "mysql", 53 | new_db = TRUE) 54 | ) 55 | rdf_add(rdf, "", "dc:name", "bob") 56 | expect_match(format(rdf, "nquads"), "bob") 57 | testthat::expect_is(rdf, "rdf") 58 | rdf_free(rdf) 59 | 60 | }) 61 | 62 | 63 | testthat::test_that("Virtuoso Backend", { 64 | testthat::skip_on_travis() 65 | testthat::skip_on_cran() 66 | 67 | testthat::skip_if_not(rdflib:::rdf_has_virtuoso()) 68 | 69 | testthat::expect_silent( 70 | r <- rdf(storage = "virtuoso", 71 | user = "dba", 72 | password = "dba", 73 | dsn = "Local Virtuoso", 74 | new_db = TRUE) 75 | ) 76 | rdf_add(r, "", "dc:name", "bob") 77 | 78 | testthat::expect_match(format(r, "nquads"), "bob") 79 | testthat::expect_is(r, "rdf") 80 | rdf_free(r) 81 | 82 | }) 83 | 84 | 85 | 86 | testthat::test_that("We warn if we cannot use disk-based storage", { 87 | testthat::skip_if(rdf_has_bdb()) 88 | skip_on_cran() 89 | 90 | 91 | testthat::expect_warning(rdf <- rdf(storage = "BDB"), "BDB driver not found") 92 | ## Falls back on memory-based storage, still creates rdf 93 | testthat::expect_is(rdf, "rdf") 94 | rdf_free(rdf) 95 | 96 | }) 97 | 98 | testthat::test_that("We can use BDB storage", { 99 | testthat::skip_if_not(rdf_has_bdb()) 100 | 101 | # not sure why this is now failing on appveyor 102 | testthat::skip_on_os("windows") 103 | skip_on_cran() 104 | 105 | 106 | testthat::expect_silent(rdf <- rdf(storage="BDB", new_db = TRUE)) 107 | 108 | rdf_add(rdf, "", "dc:name", "bob") 109 | expect_match(format(rdf, "nquads"), "bob") 110 | testthat::expect_is(rdf, "rdf") 111 | rdf_free(rdf) 112 | 113 | ## We can reconnect to disk based storage after freeing 114 | rdf2 <- rdf(storage = "BDB", new_db = FALSE) 115 | expect_match(format(rdf2, "nquads"), "bob") 116 | rdf_free(rdf2) 117 | 118 | unlink("rdflib-po2s.db") 119 | unlink("rdflib-so2p.db") 120 | unlink("rdflib-sp2o.db") 121 | }) 122 | 123 | -------------------------------------------------------------------------------- /tests/testthat/test-utilities.R: -------------------------------------------------------------------------------- 1 | context("utilities") 2 | 3 | test_that("we can correctly set prefix formats", { 4 | 5 | uri_prefix( "http://namespace.com/" ) 6 | uri_prefix( "http://namespace.com/terms#" ) 7 | 8 | expect_match( uri_prefix( "schema" ), "schema:") 9 | expect_match( uri_prefix( "schema:" ), "schema:") 10 | }) --------------------------------------------------------------------------------