FiQueLa supports ten file formats through dedicated stream classes. Each format is identified by a short key used in FQL syntax and in the Enum\Format enum.
| Key | Name | Class | File | String |
|---|
csv | CSV | FQL\Stream\Csv | Yes | No |
xml | XML | FQL\Stream\Xml | Yes | No |
xls | XLSX | FQL\Stream\Xls | Yes | No |
ods | ODS | FQL\Stream\Ods | Yes | No |
jsonFile | JSON stream | FQL\Stream\JsonStream | Yes | No |
ndJson | Newline-delimited JSON | FQL\Stream\NDJson | Yes | No |
json | JSON (json_decode) | FQL\Stream\Json | Yes | Yes |
yaml | YAML | FQL\Stream\Yaml | Yes | Yes |
neon | NEON | FQL\Stream\Neon | Yes | Yes |
log | HTTP Access Log | FQL\Stream\AccessLog | Yes | No |
json, yaml, and neon also accept raw strings via Stream\Provider::fromString(). All other formats require a file path.
You can open any format in three ways:
Stream\Provider::fromFile() — auto-detects format from the file extension, or accepts an explicit Enum\Format.
- Direct class
open() — call the class for the specific format directly.
- FQL string syntax — embed the format and path in an FQL
FROM clause.
CSV
XML
XLSX
ODS
JSON stream
NDJSON
JSON (in-memory)
YAML
NEON
HTTP access log
use FQL\Enum\Format;
use FQL\Stream;
// Auto-detect from extension
$csv = Stream\Provider::fromFile('products.csv');
// Explicit format
$csv = Stream\Provider::fromFile('data.txt', Format::CSV);
// Direct class
$csv = Stream\Csv::open('products.csv');
// With custom delimiter
$csv = Stream\Csv::openWithDelimiter('products.csv', ';');
$query = $csv->query()->selectAll()->from('*');
CSV supports format-specific parameters: encoding (default utf-8), delimiter (default ,), enclosure (default "), useHeader (default 1), and bom (default 0). Pass them via the FQL string syntax: csv(data.csv, "windows-1250", ";") or with named parameters such as csv(data.csv, enclosure: "'", bom: "1"). CSV is read and written with native PHP fgetcsv / fputcsv and detects UTF-8, UTF-16, and UTF-32 BOMs automatically.
use FQL\Enum\Format;
use FQL\Stream;
// Auto-detect from extension
$xml = Stream\Provider::fromFile('feed.xml');
// Explicit format
$xml = Stream\Provider::fromFile('data', Format::XML);
// Direct class
$xml = Stream\Xml::open('feed.xml');
// With explicit encoding
$xml = Stream\Xml::openWithEncoding('feed.xml', 'windows-1250');
$query = $xml->query()->selectAll()->from('SHOP.SHOPITEM');
XML supports the encoding parameter (default utf-8). Specify it in FQL syntax: xml(feed.xml, "windows-1250").
use FQL\Enum\Format;
use FQL\Stream;
// Auto-detect from .xlsx extension
$xls = Stream\Provider::fromFile('report.xlsx');
// Direct class
$xls = Stream\Xls::open('report.xlsx');
$query = $xls->query()->selectAll()->from('*');
Legacy .xls (Excel 97–2003 binary format) is no longer supported. Use .xlsx files instead. The underlying library is openspout/openspout.
use FQL\Enum\Format;
use FQL\Stream;
// Auto-detect from extension
$ods = Stream\Provider::fromFile('spreadsheet.ods');
// Direct class
$ods = Stream\Ods::open('spreadsheet.ods');
$query = $ods->query()->selectAll()->from('*');
use FQL\Enum\Format;
use FQL\Stream;
// Auto-detect: .json and .jsonfile extensions map to JsonStream
$json = Stream\Provider::fromFile('large-dataset.json');
// Explicit format key
$json = Stream\Provider::fromFile('data', Format::JSON_STREAM);
// Direct class
$json = Stream\JsonStream::open('large-dataset.json');
$query = $json->query()->selectAll()->from('data.items');
JsonStream uses halaxa/json-machine for streaming, making it suitable for large JSON files where loading the entire document into memory would be impractical.
use FQL\Enum\Format;
use FQL\Stream;
// Auto-detect from .ndjson extension
$ndjson = Stream\Provider::fromFile('events.ndjson');
// Direct class
$ndjson = Stream\NDJson::open('events.ndjson');
$query = $ndjson->query()->selectAll()->from('*');
use FQL\Enum\Format;
use FQL\Stream;
// From file — loads entire document via json_decode
$json = Stream\Provider::fromFile('config.json', Format::JSON);
// Direct class
$json = Stream\Json::open('config.json');
// From string
$json = Stream\Provider::fromString(
'{"users":[{"id":1,"name":"Alice"}]}',
Format::JSON
);
$query = $json->query()->selectAll()->from('users');
use FQL\Enum\Format;
use FQL\Stream;
// Auto-detect from .yaml or .yml extension
$yaml = Stream\Provider::fromFile('config.yaml');
// Direct class
$yaml = Stream\Yaml::open('config.yaml');
// From string
$yaml = Stream\Provider::fromString(
"users:\n - id: 1\n name: Alice",
Format::YAML
);
$query = $yaml->query()->selectAll()->from('users');
use FQL\Enum\Format;
use FQL\Stream;
// Auto-detect from .neon extension
$neon = Stream\Provider::fromFile('config.neon');
// Direct class
$neon = Stream\Neon::open('config.neon');
// From string
$neon = Stream\Provider::fromString(
"users:\n\t- id: 1\n\t name: Alice",
Format::NEON
);
$query = $neon->query()->selectAll()->from('users');
use FQL\Enum\Format;
use FQL\Stream;
// Auto-detect from .log extension
$log = Stream\Provider::fromFile('access.log');
// Explicit format
$log = Stream\Provider::fromFile('access.log', Format::LOG);
// Direct class — uses nginx_combined profile by default
$log = Stream\AccessLog::open('access.log');
// Switch to a different log profile
$log->setFormat('apache_common');
$query = $log->query()->selectAll()->from('*');
The log format accepts a format parameter (default nginx_combined) to select a predefined log profile. Use log(access.log, "apache_common") in FQL syntax or pass format: "custom" with a pattern parameter for custom Apache log_format patterns.
CSV, XML, and LOG accept additional configuration parameters.
CSV parameters
| Parameter | Default | Description |
|---|
encoding | utf-8 | Input file encoding. Any encoding accepted by iconv. Non-UTF-8 input is transcoded via a convert.iconv.<src>/UTF-8 PHP stream filter. |
delimiter | , | Single-character field separator. |
enclosure | " | Single-character field enclosure used by fgetcsv / fputcsv. |
useHeader | 1 | 1 to treat the first row as column headers, 0 otherwise. |
bom | 0 | 1 to emit a UTF-8 BOM when writing. The reader detects UTF-8, UTF-16 LE/BE, and UTF-32 LE/BE BOMs automatically and skips them. |
In FQL string syntax:
-- Positional
FROM csv(data.csv, "windows-1250", ";")
-- Named
FROM csv(data.csv, encoding: "windows-1250", delimiter: ";", enclosure: "'", bom: "1")
As of FiQueLa 3.0, CSV runs on native PHP primitives — the previous league/csv dependency has been dropped. Type coercion is lazy: cells stay as strings until a comparison or arithmetic operation requires a typed value, and empty cells satisfy IS NULL.
XML parameters
| Parameter | Default | Description |
|---|
encoding | utf-8 | Input file encoding. |
In FQL string syntax:
FROM xml(feed.xml, "windows-1250")
Empty XML elements
Empty leaf elements (<foo/> or <foo></foo>) surface as an empty string '', so SQL-style predicates work directly:
WHERE invoiceNumber IS NULL -- matches empty <invoiceNumber/>
WHERE invoiceNumber = '' -- matches empty <invoiceNumber/>
SELECT IF(invoiceNumber IS NULL, '', invoiceNumber) AS invoice
Elements with attributes (<foo id="1"/>) still expose their @attributes structure, mixed content (<foo id="1">text</foo>) still surfaces text under the value key, and populated leaves (<foo>text</foo>) still return their text content.
Prior to FiQueLa 3.0.1, empty leaf elements surfaced as an empty array [], which forced consumers to probe with IS ARRAY or is_array() to detect missing values. From 3.0.1 onward, they behave as empty strings — use IS NULL, = '', or IF(field IS NULL, …) instead.
LOG parameters
| Parameter | Default | Description |
|---|
format | nginx_combined | Log format profile name or custom for a custom pattern. |
pattern | — | Custom Apache log_format pattern string. Only used when format is custom. |
Predefined profiles:
| Profile | Pattern |
|---|
nginx_combined | %h - %u [%t] "%r" %>s %b "%{Referer}i" "%{User-Agent}i" (default) |
nginx_main | %h - %u [%t] "%r" %>s %b |
apache_combined | %h %l %u [%t] "%r" %>s %b "%{Referer}i" "%{User-Agent}i" |
apache_common | %h %l %u [%t] "%r" %>s %b |
In FQL string syntax:
-- Default profile (nginx_combined)
FROM log(access.log).*
-- Positional profile selection
FROM log(access.log, "apache_common").*
-- Named parameter profile selection
FROM log(access.log, format: "apache_common").*
-- Custom pattern
FROM log(access.log, format: "custom", pattern: "%h %l %u [%t] \"%r\" %>s %b").*
Automatic value normalization:
status is cast to integer
time is converted to Y-m-d H:i:s format
%D (request time in microseconds) is converted to milliseconds
%r (request line) is split into method, path, and protocol fields
Special fields in every row:
| Field | Type | Description |
|---|
_raw | string | Original unparsed log line |
_error | string | null | null on success, error message on parse failure |
Malformed log lines do not throw exceptions. Instead, they produce a row with _error containing the error message and _raw containing the original line. This allows you to filter or inspect bad lines with standard FQL conditions.
Directory provider
FQL\Stream\Dir is a special provider that treats a directory as its data source. It lets you query metadata about files recursively across a directory tree.
use FQL\Stream;
$dir = Stream\Dir::open('./data');
$query = $dir->query()
->selectAll()
->from('*');
In FQL string syntax, use the dir format key:
SELECT *
FROM dir(./data).*