Skip to content

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.

FormatFlagFile extensions
JSONanything 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):

sh
fx config.yaml
fx Cargo.toml .package.name

Input from stdin has no name, so use a flag:

sh
cat config.yaml | fx --yaml .
kubectl get pod -o yaml | fx --yaml

A flag also wins over the extension. This is handy for files with an unusual name:

sh
fx --yaml .clang-format

You 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.

sh
echo '{
  // comment
  "a": 1, /* another one */
  "b": [1, 2,],
}' | fx .
output
{
  "a": 1,
  "b": [ 1, 2 ]
}

Use --strict to reject anything that isn't valid JSON:

sh
echo '{"a": 1,}' | fx --strict .
output
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 ​

sh
echo 'name: fx
tags: [cli, json]' | fx --yaml .
output
{
  "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:

sh
echo 'name: one
---
name: two' | fx --yaml --slurp '.map(x => x.name)'
output
[ "one", "two" ]

To convert JSON back to YAML, use YAML.stringify. See also JSON to YAML and back.

TOML ​

sh
echo 'title = "Example"

[owner]
name = "Tom"
dob = 1979-05-27T07:32:00-08:00' | fx --toml .
output
{
  "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:

EDNJSON
nil, true, falsenull, true, false
"string", \cstring
:keyword, :ns/keyword, symbol"keyword", "ns/keyword", "symbol"
42N, 4.2Mnumber, suffix dropped
(list), [vector], #{set}array
{map}object
#tag valuevalue, tag dropped
##Inf, ##-Inf, ##NaNInfinity, -Infinity, NaN
#_ form, ; commentdropped
sh
echo '{:name "fx" :tags #{:cli :json} :released #inst "2020-01-01"}' | fx --edn .
output
{
  "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.

sh
echo '{
  # comment
  name: "fx"
  tags: ["cli", "json"]
}' | fx --maml .
output
{
  "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:

XMLJSON
<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"]}
sh
echo '<book id="1">
  <title>Go</title>
  <author>Alan</author>
  <author>Brian</author>
</book>' | fx --xml .
output
{
  "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:

sh
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": ...}}.

sh
echo '<p class="greeting">Hello <b>world</b></p>' | fx --html .
output
{
  "html": {
    "head": null,
    "body": {
      "p": {
        "@class": "greeting",
        "b": "world",
        "#text": "Hello"
      }
    }
  }
}

Get the links from a page:

sh
echo '<a href="/one">1</a><a href="/two">2</a>' \
| fx --html '.html.body.a.map(x => x["@href"])'
output
[ "/one", "/two" ]

Raw Text ​

With --raw (or -r), fx doesn't parse the input at all. Each line becomes a JSON string:

sh
printf 'hello\nworld\n' | fx -r 'x.toUpperCase()'
output
HELLO
WORLD

Add --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:

sh
fx config.yaml . > config.json

Or press : in the viewer and type :w config.json. See Commands.