Façade-X mapping for CSVThis document specifies how a CSV resource is represented as a Façade-X data source.
This is the editor's draft of this document. It changes with every update to the specification sources and is not a stable release. The latest release, version 0.1, is at https://w3c-facade-x.github.io/facade-x-specs/mapping-csv.html.
This document is a first draft. It follows the behaviour of the reference implementation, SPARQL Anything, and the test cases in facade-x-tests.
This document is listed in Façade-X Mappings, one of the seven Façade-X specification documents produced by the Data Façades Community Group:
A CSV resource is a sequence of records, and each record is a sequence of fields [RFC4180]. In Façade-X, the resource is a root container holding one container per record. A record container holds its fields either by position or, when headers are used, by column name.
This document applies the common principles of the format mappings.
| Prefix | Namespace |
|---|---|
| fx | http://sparql.xyz/facade-x/ns/ |
| fxe | http://sparql.xyz/facade-x/engine/ |
| xyz | http://sparql.xyz/facade-x/data/ |
| rdf | http://www.w3.org/1999/02/22-rdf-syntax-ns# |
An engine MUST apply this mapping to a resource whose media type is one of:
text/csvtext/tab-separated-valuesWhen the media type is not given, an engine SHOULD apply this mapping to resources with the file
extensions csv, tsv, and tab. For text/tab-separated-values and for the extensions tsv and
tab, the default delimiter is the tab character.
A CSV resource yields exactly one data source. Its triples are placed in the named graph whose IRI
is the value of fxe:root.
The data source has one root container, typed fx:Root.
Each record is represented by a container. The root container holds the record containers in
numbered slots, in the order of the records in the resource: the first record in rdf:_1, the
second in rdf:_2, and so on.
When fxe:csv.headers is true, the header row is not represented as a record and
the numbering starts from the first record after it.
A resource with no records yields a root container with no slots.
When fxe:csv.headers is false, each field is held by a numbered slot of its record container,
in the order of the fields in the record: the first field in rdf:_1, the second in rdf:_2, and
so on.
When fxe:csv.headers is true, each field is held by a string slot. The slot IRI is minted from
the header of the field's column, as defined in the common principles.
With the default namespace, a column headed name gives the slot xyz:name.
When fxe:csv.ignore-columns-with-no-header is true,
fields in columns without a header are not represented.
Each field value is a literal of type xsd:string. CSV defines no value types, so no other
datatype is used.
The lexical form of the literal is the content of the field after parsing:
fxe:trim-strings
is true.An empty field, quoted or not, is represented by the empty string "". It is not omitted, unless
it matches fxe:null-string or fxe:csv.null-string.
These options are terms of the Engine vocabulary and apply only to this mapping.
| Term | Range | Default | Description |
|---|---|---|---|
fxe:csv.headers |
xsd:boolean |
false | Use the values of the header row to mint slot IRIs for the fields. |
fxe:csv.headers-row |
xsd:positiveInteger |
1 | The number of the row that holds the headers. |
fxe:csv.delimiter |
xsd:string |
, (tab for tab-separated values) |
The single character that separates fields. |
fxe:csv.quote-char |
xsd:string |
" |
The single character that encloses fields. An empty string disables quoting. |
fxe:csv.null-string |
xsd:string |
— | Omit fields whose value equals the given string. |
fxe:csv.ignore-columns-with-no-header |
xsd:boolean |
false | Omit fields in columns that have no header. |
The reference implementation also supports csv.format, which selects a predefined format of the
Apache Commons CSV library, and csv.headers.sanitize. These are not part of this specification.
Input:
name,age
Alice,30
Bob,25
Façade-X representation, with default options:
@prefix fx: <http://sparql.xyz/facade-x/ns/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
[] a fx:Root ;
rdf:_1 [ rdf:_1 "name" ; rdf:_2 "age" ] ;
rdf:_2 [ rdf:_1 "Alice" ; rdf:_2 "30" ] ;
rdf:_3 [ rdf:_1 "Bob" ; rdf:_2 "25" ] .
The same input, with fxe:csv.headers set to true:
@prefix fx: <http://sparql.xyz/facade-x/ns/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix xyz: <http://sparql.xyz/facade-x/data/> .
[] a fx:Root ;
rdf:_1 [ xyz:name "Alice" ; xyz:age "30" ] ;
rdf:_2 [ xyz:name "Bob" ; xyz:age "25" ] .
Input, with fxe:csv.headers set to true:
id,name,notes
2,"Bob, Jr.",""
3,"Carol ""CJ"" Jones",
4,Dan,"first line
second line"
Façade-X representation:
@prefix fx: <http://sparql.xyz/facade-x/ns/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix xyz: <http://sparql.xyz/facade-x/data/> .
[] a fx:Root ;
rdf:_1 [ xyz:id "2" ; xyz:name "Bob, Jr." ; xyz:notes "" ] ;
rdf:_2 [ xyz:id "3" ; xyz:name "Carol \"CJ\" Jones" ; xyz:notes "" ] ;
rdf:_3 [ xyz:id "4" ; xyz:name "Dan" ; xyz:notes "first line\nsecond line" ] .
Selecting the names of people older than 26:
PREFIX fx: <http://sparql.xyz/facade-x/ns/>
PREFIX fxe: <http://sparql.xyz/facade-x/engine/>
PREFIX xyz: <http://sparql.xyz/facade-x/data/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT ?name WHERE {
SERVICE <x-sparql-anything:> {
fx:properties fxe:location "people.csv" ;
fxe:csv.headers true .
?record xyz:name ?name ;
xyz:age ?age .
FILTER (xsd:integer(?age) > 26)
}
}