Input Formats
Fx works on JSON, but it reads many other formats too. Each one is converted to JSON first, so you can view it interactively and query it with JavaScript as usual.
| Format | Flag | File extensions |
|---|---|---|
| JSON | anything else | |
| YAML | --yaml | .yaml, .yml |
| TOML | --toml | .toml |
| EDN | --edn | .edn |
| MAML | --maml | .maml |
| XML | --xml | .xml, .svg |
| HTML | --html | .html, .htm |
| Raw text | --raw |
Choosing a Format
When you open a file, fx picks the format by its extension (ignoring case):
fx config.yaml
fx Cargo.toml .package.nameInput from stdin has no name, so use a flag:
cat config.yaml | fx --yaml .
kubectl get pod -o yaml | fx --yamlA flag also wins over the extension. This is handy for files with an unusual name:
fx --yaml .clang-formatYou can only use one format flag at a time. --raw can't be combined with a format flag either.
JSON
JSON is the default. Fx reads it leniently: comments, trailing commas, Infinity, NaN, and big integers are all accepted.
echo '{
// comment
"a": 1, /* another one */
"b": [1, 2,],
}' | fx .{
"a": 1,
"b": [ 1, 2 ]
}Use --strict to reject anything that isn't valid JSON:
echo '{"a": 1,}' | fx --strict .Trailing comma is not allowed in strict mode on line 1.
{"a": 1,}
.......^Fx also reads a stream of JSON values: one per line (NDJSON) or simply concatenated. See Streaming Mode.
YAML
echo 'name: fx
tags: [cli, json]' | fx --yaml .{
"name": "fx",
"tags": [ "cli", "json" ]
}Key order is preserved, and anchors and merge keys (<<: *base) are resolved. A file with several documents separated by --- becomes a stream of JSON values; add --slurp to get them as one array:
echo 'name: one
---
name: two' | fx --yaml --slurp '.map(x => x.name)'[ "one", "two" ]To convert JSON back to YAML, use YAML.stringify. See also JSON to YAML and back.
TOML
echo 'title = "Example"
[owner]
name = "Tom"
dob = 1979-05-27T07:32:00-08:00' | fx --toml .{
"title": "Example",
"owner": {
"name": "Tom",
"dob": "1979-05-27T07:32:00-08:00"
}
}Dates and times become strings. See also TOML to JSON.
EDN
EDN is the data format of Clojure. EDN has more types than JSON, so they are mapped like this:
| EDN | JSON |
|---|---|
nil, true, false | null, true, false |
"string", \c | string |
:keyword, :ns/keyword, symbol | "keyword", "ns/keyword", "symbol" |
42N, 4.2M | number, suffix dropped |
(list), [vector], #{set} | array |
{map} | object |
#tag value | value, tag dropped |
##Inf, ##-Inf, ##NaN | Infinity, -Infinity, NaN |
#_ form, ; comment | dropped |
echo '{:name "fx" :tags #{:cli :json} :released #inst "2020-01-01"}' | fx --edn .{
"name": "fx",
"tags": [ "cli", "json" ],
"released": "2020-01-01"
}A map key that isn't a string, keyword, or symbol keeps its EDN text as the key. Several top-level forms become a stream of JSON values.
MAML
MAML is a minimal JSON-like format with comments, unquoted keys, and optional commas.
echo '{
# comment
name: "fx"
tags: ["cli", "json"]
}' | fx --maml .{
"name": "fx",
"tags": [ "cli", "json" ]
}To convert JSON back to MAML, use MAML.stringify. See also JSON to MAML and back.
XML
XML is converted the same way as Python's xmltodict:
| XML | JSON |
|---|---|
<a/>, <a></a> | "a": null |
<a>text</a> | "a": "text" |
<a k="v">text</a> | "a": {"@k": "v", "#text": "text"} |
<a><b>1</b><c/></a> | "a": {"b": "1", "c": null} |
<a><b>1</b><b>2</b></a> | "a": {"b": ["1", "2"]} |
echo '<book id="1">
<title>Go</title>
<author>Alan</author>
<author>Brian</author>
</book>' | fx --xml .{
"book": {
"@id": "1",
"title": "Go",
"author": [ "Alan", "Brian" ]
}
}All values stay strings. Text is trimmed, and whitespace between elements is dropped. Comments, processing instructions, and the DOCTYPE are dropped too. Namespace prefixes are kept in names ("svg:rect").
TIP
An element that appears once is an object, but one that repeats is an array. If the count varies, normalize it in your query: [].concat(x.book.author).
Fx opens .svg files as XML too:
fx logo.svg '.svg["@width"]'HTML
HTML is parsed the way a browser does it, then converted with the same rules as XML. The parser lowercases names, closes unclosed tags, and adds the elements HTML implies, so the result always starts with {"html": {"head": ..., "body": ...}}.
echo '<p class="greeting">Hello <b>world</b></p>' | fx --html .{
"html": {
"head": null,
"body": {
"p": {
"@class": "greeting",
"b": "world",
"#text": "Hello"
}
}
}
}Get the links from a page:
echo '<a href="/one">1</a><a href="/two">2</a>' \
| fx --html '.html.body.a.map(x => x["@href"])'[ "/one", "/two" ]Raw Text
With --raw (or -r), fx doesn't parse the input at all. Each line becomes a JSON string:
printf 'hello\nworld\n' | fx -r 'x.toUpperCase()'HELLO
WORLDAdd --slurp (or -rs) to get all lines as one array. --raw also applies to files and wins over the extension. See Non-JSON Data and Processing text with fx --raw.
Saving
Fx writes JSON only. You can't save or :w over a YAML, TOML, EDN, MAML, XML, HTML, or raw file, because that would replace it with JSON. Write to a new file instead:
fx config.yaml . > config.jsonOr press : in the viewer and type :w config.json. See Commands.