Support YAML I/O (#1963)

* docs/src/proposal-yaml-io.md

* initial step

* Add `--y2c` etc

* test cases

* docs

* more testing

* more

* more test cases

* git rm docs/src/proposal-yaml-io.md

* make dev

* ylistwrap -> yarray
This commit is contained in:
John Kerl 2026-02-15 09:24:38 -05:00 committed by GitHub
parent 0003b83654
commit f375440bd4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
93 changed files with 2108 additions and 122 deletions

View file

@ -92,19 +92,20 @@ staticcheck:
# * turns *.md.in into *.md (live code samples), using mlr from the $PATH
# * note the man/manpage.txt becomes some of the HTML content
# * turns *.md into docs/site HTML and CSS files
dev:
-make fmt
make build
dev: fmt build
make check
make -C man build
make -C docs/src forcebuild
make -C docs
@echo DONE
docs: build
docs: fmt build
make -C docs/src forcebuild
make -C docs
man: fmt build
make -C man build
# ----------------------------------------------------------------
# Keystroke-savers
@ -124,4 +125,4 @@ release_tarball: build check
# ================================================================
# Go does its own dependency management, outside of make.
.PHONY: build mlr check unit_test regression_test bench fmt staticcheck dev docs
.PHONY: build mlr check unit_test regression_test bench fmt staticcheck dev docs man

View file

@ -17,7 +17,7 @@ Quick links:
# Features
Miller is like awk, sed, cut, join, and sort for **name-indexed data, such as
CSV, TSV, JSON, and JSON Lines**. You get to work with your data using named
CSV, TSV, JSON, JSON Lines, and YAML**. You get to work with your data using named
fields, without needing to count positional column indices.
This is something the Unix toolkit always could have done, and arguably always
@ -25,7 +25,7 @@ should have done. It operates on key-value-pair data while the familiar Unix
tools operate on integer-indexed fields: if the natural data structure for the
latter is the array, then Miller's natural data structure is the
insertion-ordered hash map. This encompasses a **variety of data formats**,
including but not limited to the familiar CSV, TSV, JSON, and JSON Lines.
including but not limited to the familiar CSV, TSV, JSON, JSON Lines, and YAML.
(Miller can handle **positionally-indexed data** as a special case.)
* Miller is **multi-purpose**: it's useful for **data cleaning**, **data reduction**, **statistical reporting**, **devops**, **system administration**, **log-file processing**, **format conversion**, and **database-query post-processing**.
@ -42,7 +42,7 @@ including but not limited to the familiar CSV, TSV, JSON, and JSON Lines.
* Miller is **pipe-friendly** and interoperates with the Unix toolkit
* Miller's I/O formats include **tabular pretty-printing**, **positionally indexed** (Unix-toolkit style), CSV, JSON, and others
* Miller's I/O formats include **tabular pretty-printing**, **positionally indexed** (Unix-toolkit style), CSV, JSON, YAML, and others
* Miller does **conversion** between formats

View file

@ -1,7 +1,7 @@
# Features
Miller is like awk, sed, cut, join, and sort for **name-indexed data, such as
CSV, TSV, JSON, and JSON Lines**. You get to work with your data using named
CSV, TSV, JSON, JSON Lines, and YAML**. You get to work with your data using named
fields, without needing to count positional column indices.
This is something the Unix toolkit always could have done, and arguably always
@ -9,7 +9,7 @@ should have done. It operates on key-value-pair data while the familiar Unix
tools operate on integer-indexed fields: if the natural data structure for the
latter is the array, then Miller's natural data structure is the
insertion-ordered hash map. This encompasses a **variety of data formats**,
including but not limited to the familiar CSV, TSV, JSON, and JSON Lines.
including but not limited to the familiar CSV, TSV, JSON, JSON Lines, and YAML.
(Miller can handle **positionally-indexed data** as a special case.)
* Miller is **multi-purpose**: it's useful for **data cleaning**, **data reduction**, **statistical reporting**, **devops**, **system administration**, **log-file processing**, **format conversion**, and **database-query post-processing**.
@ -26,7 +26,7 @@ including but not limited to the familiar CSV, TSV, JSON, and JSON Lines.
* Miller is **pipe-friendly** and interoperates with the Unix toolkit
* Miller's I/O formats include **tabular pretty-printing**, **positionally indexed** (Unix-toolkit style), CSV, JSON, and others
* Miller's I/O formats include **tabular pretty-printing**, **positionally indexed** (Unix-toolkit style), CSV, JSON, YAML, and others
* Miller does **conversion** between formats

View file

@ -17,7 +17,7 @@ Quick links:
# File formats
Miller handles name-indexed data using several formats: some you probably know
by name, such as CSV, TSV, JSON, and JSON Lines -- and other formats you're likely already
by name, such as CSV, TSV, JSON, JSON Lines, and YAML -- and other formats you're likely already
seeing and using in your structured data.
Additionally, Miller gives you the option to include comments within your data.
@ -62,6 +62,16 @@ JSON Lines (sequence of one-line objects):
Record 1: "apple":"1", "bat":"2", "cog":"3"
Record 2: "dish:egg":"7", "dish:flint":"8", "garlic":""
YAML (single document = object or array of objects; multiple documents with ---):
+---------------------+
| apple: 1 |
| bat: 2 | Record 1: "apple":"1", "bat":"2", "cog":"3"
| cog: 3 |
| --- |
| dish: 7 | Record 2: "dish":"7", "egg":"8"
| egg: 8 |
+---------------------+
PPRINT: pretty-printed tabular
+---------------------+
| apple bat cog |
@ -408,6 +418,18 @@ won't reject your input data for lack of outermost `[...]`, nor will it reject y
of newlines. The difference is on _output_: using `--ojson`, you get outermost `[...]` and pretty-printed
records; using `--ojsonl`, you get no outermost `[...]`, and one line per record.
## YAML
Miller supports YAML as an I/O format in the same spirit as JSON: input can be a single YAML document
that is an object (one record) or an array of objects (one record per element), or multiple YAML
documents separated by `---` (each document is an object or array of objects). Output is either one
YAML document per record (with `---` between documents) or a single YAML document that is an array
of all records, controlled by the same kind of list-wrap behavior as JSON.
Use `--yaml`, `--iyaml`, or `--oyaml` (or `-i yaml` / `-o yaml`). Nested structures and types are
handled like JSON: nested objects become dotted keys when flattened; types are preserved through
the stream.
## PPRINT: Pretty-printed tabular
Miller's pretty-print format is similar to CSV, but with column alignment. For example, compare
@ -708,20 +730,21 @@ While you can do format conversion using `mlr --icsv --ojson cat myfile.csv`, th
<pre class="pre-non-highlight-in-pair">
FORMAT-CONVERSION KEYSTROKE-SAVER FLAGS
As keystroke-savers for format-conversion you may use the following.
The letters c, t, j, l, d, n, x, p, and m refer to formats CSV, TSV, DKVP, NIDX,
JSON, JSON Lines, XTAB, PPRINT, and markdown, respectively.
The letters c, t, j, l, d, n, x, p, m, and y refer to formats CSV, TSV, JSON, JSON Lines,
DKVP, NIDX, XTAB, PPRINT, markdown, and YAML, respectively.
| In\out | CSV | TSV | JSON | JSONL | DKVP | NIDX | XTAB | PPRINT | Markdown |
+----------+----------+----------+----------+-------+-------+-------+-------+--------+----------|
| CSV | --c2c,-c | --c2t | --c2j | --c2l | --c2d | --c2n | --c2x | --c2p | --c2m |
| TSV | --t2c | --t2t,-t | --t2j | --t2l | --t2d | --t2n | --t2x | --t2p | --t2m |
| JSON | --j2c | --j2t | --j2j,-j | --j2l | --j2d | --j2n | --j2x | --j2p | --j2m |
| JSONL | --l2c | --l2t | --l2j | --l2l | --l2d | --l2n | --l2x | --l2p | --l2m |
| DKVP | --d2c | --d2t | --d2j | --d2l | --d2d | --d2n | --d2x | --d2p | --d2m |
| NIDX | --n2c | --n2t | --n2j | --n2l | --n2d | --n2n | --n2x | --n2p | --n2m |
| XTAB | --x2c | --x2t | --x2j | --x2l | --x2d | --x2n | --x2x | --x2p | --x2m |
| PPRINT | --p2c | --p2t | --p2j | --p2l | --p2d | --p2n | --p2x | -p2p | --p2m |
| Markdown | --m2c | --m2t | --m2j | --m2l | --m2d | --m2n | --m2x | --m2p | |
| In\out | CSV | TSV | JSON | JSONL | DKVP | NIDX | XTAB | PPRINT | Markdown | YAML |
+----------+----------+----------+----------+-------+-------+-------+-------+--------+----------+--------+
| CSV | --c2c,-c | --c2t | --c2j | --c2l | --c2d | --c2n | --c2x | --c2p | --c2m | --c2y |
| TSV | --t2c | --t2t,-t | --t2j | --t2l | --t2d | --t2n | --t2x | --t2p | --t2m | --t2y |
| JSON | --j2c | --j2t | --j2j,-j | --j2l | --j2d | --j2n | --j2x | --j2p | --j2m | --j2y |
| JSONL | --l2c | --l2t | --l2j | --l2l | --l2d | --l2n | --l2x | --l2p | --l2m | --l2y |
| DKVP | --d2c | --d2t | --d2j | --d2l | --d2d | --d2n | --d2x | --d2p | --d2m | --d2y |
| NIDX | --n2c | --n2t | --n2j | --n2l | --n2d | --n2n | --n2x | --n2p | --n2m | --n2y |
| XTAB | --x2c | --x2t | --x2j | --x2l | --x2d | --x2n | --x2x | --x2p | --x2m | --x2y |
| PPRINT | --p2c | --p2t | --p2j | --p2l | --p2d | --p2n | --p2x | -p2p | --p2m | --p2y |
| Markdown | --m2c | --m2t | --m2j | --m2l | --m2d | --m2n | --m2x | --m2p | | --m2y |
| YAML | --y2c | --y2t | --y2j | --y2l | --y2d | --y2n | --y2x | --y2p | --y2m | --y2y |
-p Keystroke-saver for `--nidx --fs space --repifs`.
-T Keystroke-saver for `--nidx --fs tab`.

View file

@ -1,7 +1,7 @@
# File formats
Miller handles name-indexed data using several formats: some you probably know
by name, such as CSV, TSV, JSON, and JSON Lines -- and other formats you're likely already
by name, such as CSV, TSV, JSON, JSON Lines, and YAML -- and other formats you're likely already
seeing and using in your structured data.
Additionally, Miller gives you the option to include comments within your data.
@ -168,6 +168,18 @@ won't reject your input data for lack of outermost `[...]`, nor will it reject y
of newlines. The difference is on _output_: using `--ojson`, you get outermost `[...]` and pretty-printed
records; using `--ojsonl`, you get no outermost `[...]`, and one line per record.
## YAML
Miller supports YAML as an I/O format in the same spirit as JSON: input can be a single YAML document
that is an object (one record) or an array of objects (one record per element), or multiple YAML
documents separated by `---` (each document is an object or array of objects). Output is either one
YAML document per record (with `---` between documents) or a single YAML document that is an array
of all records, controlled by the same kind of list-wrap behavior as JSON.
Use `--yaml`, `--iyaml`, or `--oyaml` (or `-i yaml` / `-o yaml`). Nested structures and types are
handled like JSON: nested objects become dotted keys when flattened; types are preserved through
the stream.
## PPRINT: Pretty-printed tabular
Miller's pretty-print format is similar to CSV, but with column alignment. For example, compare

View file

@ -448,6 +448,10 @@ record is an object written on a single line, without need to be wrapped an
outermost list. This format helps people interoperate with non-JSON-aware
tools in the [Unix toolkit](#unix-toolkit) which generally operate on lines.
## YAML
A human-readable [file format](file-formats.md#yaml) for structured data supported by Miller. Input can be a single document (object or array of objects) or multiple documents separated by `---`. Output can be one top-level array document or one document per record.
## key
The string index in a [map](#map). Also, the name of a field in a [record](#record).
@ -464,7 +468,7 @@ trying to define a [local variable](#local-variable) `if = 3` will result in a p
A subsequence of a text file in between line-ending symbols such as the special linefeed character.
Tools in the [Unix toolkit](#unix-toolkit) generally operate on lines; Miller is designed to do
that (using the [NIDX format flags](file-formats.md#nidx-index-numbered-toolkit-style)), as well
as non-line-oriented formats such as [CSV, TSV, JSON, and others](file-formats.md).
as non-line-oriented formats such as [CSV, TSV, JSON, YAML, and others](file-formats.md).
## local variable

View file

@ -432,6 +432,10 @@ record is an object written on a single line, without need to be wrapped an
outermost list. This format helps people interoperate with non-JSON-aware
tools in the [Unix toolkit](#unix-toolkit) which generally operate on lines.
## YAML
A human-readable [file format](file-formats.md#yaml) for structured data supported by Miller. Input can be a single document (object or array of objects) or multiple documents separated by `---`. Output can be one top-level array document or one document per record.
## key
The string index in a [map](#map). Also, the name of a field in a [record](#record).
@ -448,7 +452,7 @@ trying to define a [local variable](#local-variable) `if = 3` will result in a p
A subsequence of a text file in between line-ending symbols such as the special linefeed character.
Tools in the [Unix toolkit](#unix-toolkit) generally operate on lines; Miller is designed to do
that (using the [NIDX format flags](file-formats.md#nidx-index-numbered-toolkit-style)), as well
as non-line-oriented formats such as [CSV, TSV, JSON, and others](file-formats.md).
as non-line-oriented formats such as [CSV, TSV, JSON, YAML, and others](file-formats.md).
## local variable

View file

@ -16,7 +16,7 @@ Quick links:
</div>
# Introduction
**Miller is a command-line tool for querying, shaping, and reformatting data files in various formats, including CSV, TSV, JSON, and JSON Lines.**
**Miller is a command-line tool for querying, shaping, and reformatting data files in various formats, including CSV, TSV, JSON, JSON Lines, and YAML.**
**The big picture:** Even well into the 21st century, our world is full of text-formatted data such as CSV. Google _CSV memes_, for example. We need tooling to _thrive in this world_, nimbly manipulating data which is in CSVs. And we need tooling to _move beyond CSV_, to be able to pull data out and into other storage and processing systems. Miller is designed for both of these goals.
@ -39,7 +39,7 @@ pretty-print your data horizontally or vertically to make it easier to read.
<b>mlr --json head -n 1 myfile.json</b>
</pre>
The `sort`, `head`, etc., are called *verbs*. They're analogs of familiar command-line tools like `sort`, `head`, and so on -- but they're aware of name-indexed, multi-line file formats like CSV, TSV, and JSON. In addition, though, using Miller's `put` verb, you can use programming-language statements for expressions like
The `sort`, `head`, etc., are called *verbs*. They're analogs of familiar command-line tools like `sort`, `head`, and so on -- but they're aware of name-indexed, multi-line file formats like CSV, TSV, JSON, and YAML. In addition, though, using Miller's `put` verb, you can use programming-language statements for expressions like
<pre class="pre-highlight-non-pair">
<b>mlr --csv put '$rate = $units / $seconds' input.csv</b>

View file

@ -1,6 +1,6 @@
# Introduction
**Miller is a command-line tool for querying, shaping, and reformatting data files in various formats, including CSV, TSV, JSON, and JSON Lines.**
**Miller is a command-line tool for querying, shaping, and reformatting data files in various formats, including CSV, TSV, JSON, JSON Lines, and YAML.**
**The big picture:** Even well into the 21st century, our world is full of text-formatted data such as CSV. Google _CSV memes_, for example. We need tooling to _thrive in this world_, nimbly manipulating data which is in CSVs. And we need tooling to _move beyond CSV_, to be able to pull data out and into other storage and processing systems. Miller is designed for both of these goals.
@ -23,7 +23,7 @@ GENMD-SHOW-COMMAND
mlr --json head -n 1 myfile.json
GENMD-EOF
The `sort`, `head`, etc., are called *verbs*. They're analogs of familiar command-line tools like `sort`, `head`, and so on -- but they're aware of name-indexed, multi-line file formats like CSV, TSV, and JSON. In addition, though, using Miller's `put` verb, you can use programming-language statements for expressions like
The `sort`, `head`, etc., are called *verbs*. They're analogs of familiar command-line tools like `sort`, `head`, and so on -- but they're aware of name-indexed, multi-line file formats like CSV, TSV, JSON, and YAML. In addition, though, using Miller's `put` verb, you can use programming-language statements for expressions like
GENMD-SHOW-COMMAND
mlr --csv put '$rate = $units / $seconds' input.csv

View file

@ -94,6 +94,16 @@ This is simply a copy of what you should see on running `man mlr` at a command p
Record 1: "apple":"1", "bat":"2", "cog":"3"
Record 2: "dish:egg":"7", "dish:flint":"8", "garlic":""
YAML (single document = object or array of objects; multiple documents with ---):
+---------------------+
| apple: 1 |
| bat: 2 | Record 1: "apple":"1", "bat":"2", "cog":"3"
| cog: 3 |
| --- |
| dish: 7 | Record 2: "dish":"7", "egg":"8"
| egg: 8 |
+---------------------+
PPRINT: pretty-printed tabular
+---------------------+
| apple bat cog |
@ -407,6 +417,7 @@ This is simply a copy of what you should see on running `man mlr` at a command p
--itsvlite Use TSV-lite format for input data.
--iusv or --iusvlite Use USV format for input data.
--ixtab Use XTAB format for input data.
--iyaml Use YAML format for input data.
--json or -j or --j2j Use JSON format for input and output data.
--jsonl or --l2l Use JSON Lines format for input and output data.
--nidx or --n2n Use NIDX format for input and output data.
@ -423,12 +434,14 @@ This is simply a copy of what you should see on running `man mlr` at a command p
--otsvlite Use TSV-lite format for output data.
--ousv or --ousvlite Use USV format for output data.
--oxtab Use XTAB format for output data.
--oyaml Use YAML format for output data.
--pprint or --p2p Use PPRINT format for input and output data.
--tsv or -t or --t2t Use TSV format for input and output data.
--tsvlite Use TSV-lite format for input and output data.
--usv or --usvlite Use USV format for input and output data.
--xtab or --x2x Use XTAB format for input and output data.
--xvright Right-justify values for XTAB format.
--yaml or --y2y Use YAML format for input and output data.
-i {format name} Use format name for input data. For example: `-i csv`
is the same as `--icsv`.
-o {format name} Use format name for output data. For example: `-o
@ -456,20 +469,21 @@ This is simply a copy of what you should see on running `man mlr` at a command p
1mFORMAT-CONVERSION KEYSTROKE-SAVER FLAGS0m
As keystroke-savers for format-conversion you may use the following.
The letters c, t, j, l, d, n, x, p, and m refer to formats CSV, TSV, DKVP, NIDX,
JSON, JSON Lines, XTAB, PPRINT, and markdown, respectively.
The letters c, t, j, l, d, n, x, p, m, and y refer to formats CSV, TSV, JSON, JSON Lines,
DKVP, NIDX, XTAB, PPRINT, markdown, and YAML, respectively.
| In\out | CSV | TSV | JSON | JSONL | DKVP | NIDX | XTAB | PPRINT | Markdown |
+----------+----------+----------+----------+-------+-------+-------+-------+--------+----------|
| CSV | --c2c,-c | --c2t | --c2j | --c2l | --c2d | --c2n | --c2x | --c2p | --c2m |
| TSV | --t2c | --t2t,-t | --t2j | --t2l | --t2d | --t2n | --t2x | --t2p | --t2m |
| JSON | --j2c | --j2t | --j2j,-j | --j2l | --j2d | --j2n | --j2x | --j2p | --j2m |
| JSONL | --l2c | --l2t | --l2j | --l2l | --l2d | --l2n | --l2x | --l2p | --l2m |
| DKVP | --d2c | --d2t | --d2j | --d2l | --d2d | --d2n | --d2x | --d2p | --d2m |
| NIDX | --n2c | --n2t | --n2j | --n2l | --n2d | --n2n | --n2x | --n2p | --n2m |
| XTAB | --x2c | --x2t | --x2j | --x2l | --x2d | --x2n | --x2x | --x2p | --x2m |
| PPRINT | --p2c | --p2t | --p2j | --p2l | --p2d | --p2n | --p2x | -p2p | --p2m |
| Markdown | --m2c | --m2t | --m2j | --m2l | --m2d | --m2n | --m2x | --m2p | |
| In\out | CSV | TSV | JSON | JSONL | DKVP | NIDX | XTAB | PPRINT | Markdown | YAML |
+----------+----------+----------+----------+-------+-------+-------+-------+--------+----------+--------+
| CSV | --c2c,-c | --c2t | --c2j | --c2l | --c2d | --c2n | --c2x | --c2p | --c2m | --c2y |
| TSV | --t2c | --t2t,-t | --t2j | --t2l | --t2d | --t2n | --t2x | --t2p | --t2m | --t2y |
| JSON | --j2c | --j2t | --j2j,-j | --j2l | --j2d | --j2n | --j2x | --j2p | --j2m | --j2y |
| JSONL | --l2c | --l2t | --l2j | --l2l | --l2d | --l2n | --l2x | --l2p | --l2m | --l2y |
| DKVP | --d2c | --d2t | --d2j | --d2l | --d2d | --d2n | --d2x | --d2p | --d2m | --d2y |
| NIDX | --n2c | --n2t | --n2j | --n2l | --n2d | --n2n | --n2x | --n2p | --n2m | --n2y |
| XTAB | --x2c | --x2t | --x2j | --x2l | --x2d | --x2n | --x2x | --x2p | --x2m | --x2y |
| PPRINT | --p2c | --p2t | --p2j | --p2l | --p2d | --p2n | --p2x | -p2p | --p2m | --p2y |
| Markdown | --m2c | --m2t | --m2j | --m2l | --m2d | --m2n | --m2x | --m2p | | --m2y |
| YAML | --y2c | --y2t | --y2j | --y2l | --y2d | --y2n | --y2x | --y2p | --y2m | --y2y |
-p Keystroke-saver for `--nidx --fs space --repifs`.
-T Keystroke-saver for `--nidx --fs tab`.
@ -488,6 +502,10 @@ This is simply a copy of what you should see on running `man mlr` at a command p
the default for JSON Lines output format.
--no-jvstack Put objects/arrays all on one line for JSON output.
This is the default for JSON Lines output format.
--no-yarray Do not wrap YAML output in a single array document;
emit one YAML document per record with `---` between.
--yarray or --ya Wrap YAML output in a single top-level array
document. This is the default for YAML output format.
1mLEGACY FLAGS0m
These are flags which don't do anything in the current Miller version.
@ -827,6 +845,7 @@ This is simply a copy of what you should see on running `man mlr` at a command p
pprint " " N/A "\n"
tsv " " N/A "\n"
xtab "\n" " " "\n\n"
yaml N/A N/A N/A
--fs {string} Specify FS for input and output.
--ifs {string} Specify FS for input.

View file

@ -73,6 +73,16 @@
Record 1: "apple":"1", "bat":"2", "cog":"3"
Record 2: "dish:egg":"7", "dish:flint":"8", "garlic":""
YAML (single document = object or array of objects; multiple documents with ---):
+---------------------+
| apple: 1 |
| bat: 2 | Record 1: "apple":"1", "bat":"2", "cog":"3"
| cog: 3 |
| --- |
| dish: 7 | Record 2: "dish":"7", "egg":"8"
| egg: 8 |
+---------------------+
PPRINT: pretty-printed tabular
+---------------------+
| apple bat cog |
@ -386,6 +396,7 @@
--itsvlite Use TSV-lite format for input data.
--iusv or --iusvlite Use USV format for input data.
--ixtab Use XTAB format for input data.
--iyaml Use YAML format for input data.
--json or -j or --j2j Use JSON format for input and output data.
--jsonl or --l2l Use JSON Lines format for input and output data.
--nidx or --n2n Use NIDX format for input and output data.
@ -402,12 +413,14 @@
--otsvlite Use TSV-lite format for output data.
--ousv or --ousvlite Use USV format for output data.
--oxtab Use XTAB format for output data.
--oyaml Use YAML format for output data.
--pprint or --p2p Use PPRINT format for input and output data.
--tsv or -t or --t2t Use TSV format for input and output data.
--tsvlite Use TSV-lite format for input and output data.
--usv or --usvlite Use USV format for input and output data.
--xtab or --x2x Use XTAB format for input and output data.
--xvright Right-justify values for XTAB format.
--yaml or --y2y Use YAML format for input and output data.
-i {format name} Use format name for input data. For example: `-i csv`
is the same as `--icsv`.
-o {format name} Use format name for output data. For example: `-o
@ -435,20 +448,21 @@
1mFORMAT-CONVERSION KEYSTROKE-SAVER FLAGS0m
As keystroke-savers for format-conversion you may use the following.
The letters c, t, j, l, d, n, x, p, and m refer to formats CSV, TSV, DKVP, NIDX,
JSON, JSON Lines, XTAB, PPRINT, and markdown, respectively.
The letters c, t, j, l, d, n, x, p, m, and y refer to formats CSV, TSV, JSON, JSON Lines,
DKVP, NIDX, XTAB, PPRINT, markdown, and YAML, respectively.
| In\out | CSV | TSV | JSON | JSONL | DKVP | NIDX | XTAB | PPRINT | Markdown |
+----------+----------+----------+----------+-------+-------+-------+-------+--------+----------|
| CSV | --c2c,-c | --c2t | --c2j | --c2l | --c2d | --c2n | --c2x | --c2p | --c2m |
| TSV | --t2c | --t2t,-t | --t2j | --t2l | --t2d | --t2n | --t2x | --t2p | --t2m |
| JSON | --j2c | --j2t | --j2j,-j | --j2l | --j2d | --j2n | --j2x | --j2p | --j2m |
| JSONL | --l2c | --l2t | --l2j | --l2l | --l2d | --l2n | --l2x | --l2p | --l2m |
| DKVP | --d2c | --d2t | --d2j | --d2l | --d2d | --d2n | --d2x | --d2p | --d2m |
| NIDX | --n2c | --n2t | --n2j | --n2l | --n2d | --n2n | --n2x | --n2p | --n2m |
| XTAB | --x2c | --x2t | --x2j | --x2l | --x2d | --x2n | --x2x | --x2p | --x2m |
| PPRINT | --p2c | --p2t | --p2j | --p2l | --p2d | --p2n | --p2x | -p2p | --p2m |
| Markdown | --m2c | --m2t | --m2j | --m2l | --m2d | --m2n | --m2x | --m2p | |
| In\out | CSV | TSV | JSON | JSONL | DKVP | NIDX | XTAB | PPRINT | Markdown | YAML |
+----------+----------+----------+----------+-------+-------+-------+-------+--------+----------+--------+
| CSV | --c2c,-c | --c2t | --c2j | --c2l | --c2d | --c2n | --c2x | --c2p | --c2m | --c2y |
| TSV | --t2c | --t2t,-t | --t2j | --t2l | --t2d | --t2n | --t2x | --t2p | --t2m | --t2y |
| JSON | --j2c | --j2t | --j2j,-j | --j2l | --j2d | --j2n | --j2x | --j2p | --j2m | --j2y |
| JSONL | --l2c | --l2t | --l2j | --l2l | --l2d | --l2n | --l2x | --l2p | --l2m | --l2y |
| DKVP | --d2c | --d2t | --d2j | --d2l | --d2d | --d2n | --d2x | --d2p | --d2m | --d2y |
| NIDX | --n2c | --n2t | --n2j | --n2l | --n2d | --n2n | --n2x | --n2p | --n2m | --n2y |
| XTAB | --x2c | --x2t | --x2j | --x2l | --x2d | --x2n | --x2x | --x2p | --x2m | --x2y |
| PPRINT | --p2c | --p2t | --p2j | --p2l | --p2d | --p2n | --p2x | -p2p | --p2m | --p2y |
| Markdown | --m2c | --m2t | --m2j | --m2l | --m2d | --m2n | --m2x | --m2p | | --m2y |
| YAML | --y2c | --y2t | --y2j | --y2l | --y2d | --y2n | --y2x | --y2p | --y2m | --y2y |
-p Keystroke-saver for `--nidx --fs space --repifs`.
-T Keystroke-saver for `--nidx --fs tab`.
@ -467,6 +481,10 @@
the default for JSON Lines output format.
--no-jvstack Put objects/arrays all on one line for JSON output.
This is the default for JSON Lines output format.
--no-yarray Do not wrap YAML output in a single array document;
emit one YAML document per record with `---` between.
--yarray or --ya Wrap YAML output in a single top-level array
document. This is the default for YAML output format.
1mLEGACY FLAGS0m
These are flags which don't do anything in the current Miller version.
@ -806,6 +824,7 @@
pprint " " N/A "\n"
tsv " " N/A "\n"
xtab "\n" " " "\n\n"
yaml N/A N/A N/A
--fs {string} Specify FS for input and output.
--ifs {string} Specify FS for input.

View file

@ -15,19 +15,22 @@ for section_name in section_names
if section_name =~ /.*conversion.*keystroke-saver*/
# The markdown in this section looks a lot better when hand-crafted (thanks Nikos!).
puts <<EOF
The letters `c`, `t`, `j`, `d`, `n`, `x`, `p`, and `m` refer to formats CSV, TSV, DKVP, NIDX, JSON, XTAB,
PPRINT, and markdown, respectively. Note that markdown format is available for
The letters `c`, `t`, `j`, `l`, `d`, `n`, `x`, `p`, `m`, and `y` refer to formats CSV, TSV, JSON, JSON Lines,
DKVP, NIDX, XTAB, PPRINT, markdown, and YAML, respectively. Note that markdown format is available for
output only.
| In \ out | **CSV** | **TSV** | **JSON** | **DKVP** | **NIDX** | **XTAB** | **PPRINT** | **Markdown** |
|------------|---------|---------|----------|----------|----------|----------|------------|--------------|
| **CSV** | | `--c2t` | `--c2j` | `--c2d` | `--c2n` | `--c2x` | `--c2p` | `--c2m` |
| **TSV** | `--t2c` | | `--t2j` | `--t2d` | `--t2n` | `--t2x` | `--t2p` | `--t2m` |
| **JSON** | `--j2c` | `--j2t` | | `--j2d` | `--j2n` | `--j2x` | `--j2p` | `--j2m` |
| **DKVP** | `--d2c` | `--d2t` | `--d2j` | | `--d2n` | `--d2x` | `--d2p` | `--d2m` |
| **NIDX** | `--n2c` | `--n2t` | `--n2j` | `--n2d` | | `--n2x` | `--n2p` | `--n2m` |
| **XTAB** | `--x2c` | `--x2t` | `--x2j` | `--x2d` | `--x2n` | | `--x2p` | `--x2m` |
| **PPRINT** | `--p2c` | `--p2t` | `--p2j` | `--p2d` | `--p2n` | `--p2x` | | `--p2m` |
| In \\ out | **CSV** | **TSV** | **JSON** | **JSONL** | **DKVP** | **NIDX** | **XTAB** | **PPRINT** | **Markdown** | **YAML** |
|------------|---------|---------|----------|-----------|----------|----------|----------|------------|--------------|----------|
| **CSV** | | `--c2t` | `--c2j` | `--c2l` | `--c2d` | `--c2n` | `--c2x` | `--c2p` | `--c2m` | `--c2y` |
| **TSV** | `--t2c` | | `--t2j` | `--t2l` | `--t2d` | `--t2n` | `--t2x` | `--t2p` | `--t2m` | `--t2y` |
| **JSON** | `--j2c` | `--j2t` | | `--j2l` | `--j2d` | `--j2n` | `--j2x` | `--j2p` | `--j2m` | `--j2y` |
| **JSONL** | `--l2c` | `--l2t` | `--l2j` | | `--l2d` | `--l2n` | `--l2x` | `--l2p` | `--l2m` | `--l2y` |
| **DKVP** | `--d2c` | `--d2t` | `--d2j` | `--d2l` | | `--d2n` | `--d2x` | `--d2p` | `--d2m` | `--d2y` |
| **NIDX** | `--n2c` | `--n2t` | `--n2j` | `--n2l` | `--n2d` | | `--n2x` | `--n2p` | `--n2m` | `--n2y` |
| **XTAB** | `--x2c` | `--x2t` | `--x2j` | `--x2l` | `--x2d` | `--x2n` | | `--x2p` | `--x2m` | `--x2y` |
| **PPRINT** | `--p2c` | `--p2t` | `--p2j` | `--p2l` | `--p2d` | `--p2n` | `--p2x` | | `--p2m` | `--p2y` |
| **Markdown** | `--m2c` | `--m2t` | `--m2j` | `--m2l` | `--m2d` | `--m2n` | `--m2x` | `--m2p` | | `--m2y` |
| **YAML** | `--y2c` | `--y2t` | `--y2j` | `--y2l` | `--y2d` | `--y2n` | `--y2x` | `--y2p` | `--y2m` | `--y2y` |
Additionally:

View file

@ -175,6 +175,7 @@ are overridden in all cases by setting output format to `format2`.
* `--itsvlite`: Use TSV-lite format for input data.
* `--iusv or --iusvlite`: Use USV format for input data.
* `--ixtab`: Use XTAB format for input data.
* `--iyaml`: Use YAML format for input data.
* `--json or -j or --j2j`: Use JSON format for input and output data.
* `--jsonl or --l2l`: Use JSON Lines format for input and output data.
* `--nidx or --n2n`: Use NIDX format for input and output data.
@ -191,12 +192,14 @@ are overridden in all cases by setting output format to `format2`.
* `--otsvlite`: Use TSV-lite format for output data.
* `--ousv or --ousvlite`: Use USV format for output data.
* `--oxtab`: Use XTAB format for output data.
* `--oyaml`: Use YAML format for output data.
* `--pprint or --p2p`: Use PPRINT format for input and output data.
* `--tsv or -t or --t2t`: Use TSV format for input and output data.
* `--tsvlite`: Use TSV-lite format for input and output data.
* `--usv or --usvlite`: Use USV format for input and output data.
* `--xtab or --x2x`: Use XTAB format for input and output data.
* `--xvright`: Right-justify values for XTAB format.
* `--yaml or --y2y`: Use YAML format for input and output data.
* `-i {format name}`: Use format name for input data. For example: `-i csv` is the same as `--icsv`.
* `-o {format name}`: Use format name for output data. For example: `-o csv` is the same as `--ocsv`.
@ -215,19 +218,22 @@ See the flatten/unflatten doc page https://miller.readthedocs.io/en/latest/flatt
## Format-conversion keystroke-saver flags
The letters `c`, `t`, `j`, `d`, `n`, `x`, `p`, and `m` refer to formats CSV, TSV, DKVP, NIDX, JSON, XTAB,
PPRINT, and markdown, respectively. Note that markdown format is available for
The letters `c`, `t`, `j`, `l`, `d`, `n`, `x`, `p`, `m`, and `y` refer to formats CSV, TSV, JSON, JSON Lines,
DKVP, NIDX, XTAB, PPRINT, markdown, and YAML, respectively. Note that markdown format is available for
output only.
| In out | **CSV** | **TSV** | **JSON** | **DKVP** | **NIDX** | **XTAB** | **PPRINT** | **Markdown** |
|------------|---------|---------|----------|----------|----------|----------|------------|--------------|
| **CSV** | | `--c2t` | `--c2j` | `--c2d` | `--c2n` | `--c2x` | `--c2p` | `--c2m` |
| **TSV** | `--t2c` | | `--t2j` | `--t2d` | `--t2n` | `--t2x` | `--t2p` | `--t2m` |
| **JSON** | `--j2c` | `--j2t` | | `--j2d` | `--j2n` | `--j2x` | `--j2p` | `--j2m` |
| **DKVP** | `--d2c` | `--d2t` | `--d2j` | | `--d2n` | `--d2x` | `--d2p` | `--d2m` |
| **NIDX** | `--n2c` | `--n2t` | `--n2j` | `--n2d` | | `--n2x` | `--n2p` | `--n2m` |
| **XTAB** | `--x2c` | `--x2t` | `--x2j` | `--x2d` | `--x2n` | | `--x2p` | `--x2m` |
| **PPRINT** | `--p2c` | `--p2t` | `--p2j` | `--p2d` | `--p2n` | `--p2x` | | `--p2m` |
| In \ out | **CSV** | **TSV** | **JSON** | **JSONL** | **DKVP** | **NIDX** | **XTAB** | **PPRINT** | **Markdown** | **YAML** |
|------------|---------|---------|----------|-----------|----------|----------|----------|------------|--------------|----------|
| **CSV** | | `--c2t` | `--c2j` | `--c2l` | `--c2d` | `--c2n` | `--c2x` | `--c2p` | `--c2m` | `--c2y` |
| **TSV** | `--t2c` | | `--t2j` | `--t2l` | `--t2d` | `--t2n` | `--t2x` | `--t2p` | `--t2m` | `--t2y` |
| **JSON** | `--j2c` | `--j2t` | | `--j2l` | `--j2d` | `--j2n` | `--j2x` | `--j2p` | `--j2m` | `--j2y` |
| **JSONL** | `--l2c` | `--l2t` | `--l2j` | | `--l2d` | `--l2n` | `--l2x` | `--l2p` | `--l2m` | `--l2y` |
| **DKVP** | `--d2c` | `--d2t` | `--d2j` | `--d2l` | | `--d2n` | `--d2x` | `--d2p` | `--d2m` | `--d2y` |
| **NIDX** | `--n2c` | `--n2t` | `--n2j` | `--n2l` | `--n2d` | | `--n2x` | `--n2p` | `--n2m` | `--n2y` |
| **XTAB** | `--x2c` | `--x2t` | `--x2j` | `--x2l` | `--x2d` | `--x2n` | | `--x2p` | `--x2m` | `--x2y` |
| **PPRINT** | `--p2c` | `--p2t` | `--p2j` | `--p2l` | `--p2d` | `--p2n` | `--p2x` | | `--p2m` | `--p2y` |
| **Markdown** | `--m2c` | `--m2t` | `--m2j` | `--m2l` | `--m2d` | `--m2n` | `--m2x` | `--m2p` | | `--m2y` |
| **YAML** | `--y2c` | `--y2t` | `--y2j` | `--y2l` | `--y2d` | `--y2n` | `--y2x` | `--y2p` | `--y2m` | `--y2y` |
Additionally:
@ -246,6 +252,8 @@ These are flags which are applicable to JSON output format.
* `--jvstack`: Put one key-value pair per line for JSON output (multi-line output). This is the default for JSON output format.
* `--no-jlistwrap`: Do not wrap JSON output in outermost `[ ]`. This is the default for JSON Lines output format.
* `--no-jvstack`: Put objects/arrays all on one line for JSON output. This is the default for JSON Lines output format.
* `--no-yarray`: Do not wrap YAML output in a single array document; emit one YAML document per record with `---` between.
* `--yarray or --ya`: Wrap YAML output in a single top-level array document. This is the default for YAML output format.
## Legacy flags
@ -494,6 +502,7 @@ Notes about all other separators:
pprint " " N/A "\n"
tsv " " N/A "\n"
xtab "\n" " " "\n\n"
yaml N/A N/A N/A
**Flags:**

View file

@ -264,7 +264,7 @@ Notes:
* CSV IRS and ORS must be newline, and CSV IFS must be a single character. (CSV-lite does not have these restrictions.)
* TSV IRS and ORS must be newline, and TSV IFS must be a tab. (TSV-lite does not have these restrictions.)
* See the [CSV section](file-formats.md#csvtsvasvusvetc) for information about ASV and USV.
* JSON: ignores all separator flags from the command line.
* JSON and YAML: ignore separator flags from the command line.
* Headerless CSV overlaps quite a bit with NIDX format using comma for IFS. See also the page on [CSV with and without headers](csv-with-and-without-headers.md).
* For XTAB, the record separator is a repetition of the field separator. For example, if one record has `x=1,y=2` and the next has `x=3,y=4`, and OFS is newline, then output lines are `x 1`, then `y 2`, then an extra newline, then `x 3`, then `y 4`. This means: to customize XTAB, set `OFS` rather than `ORS`.
@ -275,6 +275,7 @@ Notes:
| [**CSV-lite**](file-formats.md#csvtsvasvusvetc) | Default `\n` * | Default `,` | None |
| [**TSV-lite**](file-formats.md#csvtsvasvusvetc) | Default `\n` * | Default `\t` | None |
| [**JSON**](file-formats.md#json) | N/A; records are between `{` and `}` | Always `,`; not alterable | Always `:`; not alterable |
| [**YAML**](file-formats.md#yaml) | N/A; documents separated by `---` or single array | N/A; not alterable | Always `:`; not alterable |
| [**DKVP**](file-formats.md#dkvp-key-value-pairs) | Default `\n` | Default `,` | Default `=` |
| [**NIDX**](file-formats.md#nidx-index-numbered-toolkit-style) | Default `\n` | Default space | None |
| [**XTAB**](file-formats.md#xtab-vertical-tabular) | Not used; records are separated by an extra FS | `\n` * | Default: space with repeats |

View file

@ -154,7 +154,7 @@ Notes:
* CSV IRS and ORS must be newline, and CSV IFS must be a single character. (CSV-lite does not have these restrictions.)
* TSV IRS and ORS must be newline, and TSV IFS must be a tab. (TSV-lite does not have these restrictions.)
* See the [CSV section](file-formats.md#csvtsvasvusvetc) for information about ASV and USV.
* JSON: ignores all separator flags from the command line.
* JSON and YAML: ignore separator flags from the command line.
* Headerless CSV overlaps quite a bit with NIDX format using comma for IFS. See also the page on [CSV with and without headers](csv-with-and-without-headers.md).
* For XTAB, the record separator is a repetition of the field separator. For example, if one record has `x=1,y=2` and the next has `x=3,y=4`, and OFS is newline, then output lines are `x 1`, then `y 2`, then an extra newline, then `x 3`, then `y 4`. This means: to customize XTAB, set `OFS` rather than `ORS`.
@ -165,6 +165,7 @@ Notes:
| [**CSV-lite**](file-formats.md#csvtsvasvusvetc) | Default `\n` * | Default `,` | None |
| [**TSV-lite**](file-formats.md#csvtsvasvusvetc) | Default `\n` * | Default `\t` | None |
| [**JSON**](file-formats.md#json) | N/A; records are between `{` and `}` | Always `,`; not alterable | Always `:`; not alterable |
| [**YAML**](file-formats.md#yaml) | N/A; documents separated by `---` or single array | N/A; not alterable | Always `:`; not alterable |
| [**DKVP**](file-formats.md#dkvp-key-value-pairs) | Default `\n` | Default `,` | Default `=` |
| [**NIDX**](file-formats.md#nidx-index-numbered-toolkit-style) | Default `\n` | Default space | None |
| [**XTAB**](file-formats.md#xtab-vertical-tabular) | Not used; records are separated by an extra FS | `\n` * | Default: space with repeats |

2
go.mod
View file

@ -30,6 +30,7 @@ require (
golang.org/x/sys v0.41.0
golang.org/x/term v0.40.0
golang.org/x/text v0.34.0
gopkg.in/yaml.v3 v3.0.1
)
require (
@ -41,5 +42,4 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/tools v0.41.0 // indirect
gonum.org/v1/gonum v0.16.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View file

@ -73,6 +73,16 @@
Record 1: "apple":"1", "bat":"2", "cog":"3"
Record 2: "dish:egg":"7", "dish:flint":"8", "garlic":""
YAML (single document = object or array of objects; multiple documents with ---):
+---------------------+
| apple: 1 |
| bat: 2 | Record 1: "apple":"1", "bat":"2", "cog":"3"
| cog: 3 |
| --- |
| dish: 7 | Record 2: "dish":"7", "egg":"8"
| egg: 8 |
+---------------------+
PPRINT: pretty-printed tabular
+---------------------+
| apple bat cog |
@ -386,6 +396,7 @@
--itsvlite Use TSV-lite format for input data.
--iusv or --iusvlite Use USV format for input data.
--ixtab Use XTAB format for input data.
--iyaml Use YAML format for input data.
--json or -j or --j2j Use JSON format for input and output data.
--jsonl or --l2l Use JSON Lines format for input and output data.
--nidx or --n2n Use NIDX format for input and output data.
@ -402,12 +413,14 @@
--otsvlite Use TSV-lite format for output data.
--ousv or --ousvlite Use USV format for output data.
--oxtab Use XTAB format for output data.
--oyaml Use YAML format for output data.
--pprint or --p2p Use PPRINT format for input and output data.
--tsv or -t or --t2t Use TSV format for input and output data.
--tsvlite Use TSV-lite format for input and output data.
--usv or --usvlite Use USV format for input and output data.
--xtab or --x2x Use XTAB format for input and output data.
--xvright Right-justify values for XTAB format.
--yaml or --y2y Use YAML format for input and output data.
-i {format name} Use format name for input data. For example: `-i csv`
is the same as `--icsv`.
-o {format name} Use format name for output data. For example: `-o
@ -435,20 +448,21 @@
1mFORMAT-CONVERSION KEYSTROKE-SAVER FLAGS0m
As keystroke-savers for format-conversion you may use the following.
The letters c, t, j, l, d, n, x, p, and m refer to formats CSV, TSV, DKVP, NIDX,
JSON, JSON Lines, XTAB, PPRINT, and markdown, respectively.
The letters c, t, j, l, d, n, x, p, m, and y refer to formats CSV, TSV, JSON, JSON Lines,
DKVP, NIDX, XTAB, PPRINT, markdown, and YAML, respectively.
| In\out | CSV | TSV | JSON | JSONL | DKVP | NIDX | XTAB | PPRINT | Markdown |
+----------+----------+----------+----------+-------+-------+-------+-------+--------+----------|
| CSV | --c2c,-c | --c2t | --c2j | --c2l | --c2d | --c2n | --c2x | --c2p | --c2m |
| TSV | --t2c | --t2t,-t | --t2j | --t2l | --t2d | --t2n | --t2x | --t2p | --t2m |
| JSON | --j2c | --j2t | --j2j,-j | --j2l | --j2d | --j2n | --j2x | --j2p | --j2m |
| JSONL | --l2c | --l2t | --l2j | --l2l | --l2d | --l2n | --l2x | --l2p | --l2m |
| DKVP | --d2c | --d2t | --d2j | --d2l | --d2d | --d2n | --d2x | --d2p | --d2m |
| NIDX | --n2c | --n2t | --n2j | --n2l | --n2d | --n2n | --n2x | --n2p | --n2m |
| XTAB | --x2c | --x2t | --x2j | --x2l | --x2d | --x2n | --x2x | --x2p | --x2m |
| PPRINT | --p2c | --p2t | --p2j | --p2l | --p2d | --p2n | --p2x | -p2p | --p2m |
| Markdown | --m2c | --m2t | --m2j | --m2l | --m2d | --m2n | --m2x | --m2p | |
| In\out | CSV | TSV | JSON | JSONL | DKVP | NIDX | XTAB | PPRINT | Markdown | YAML |
+----------+----------+----------+----------+-------+-------+-------+-------+--------+----------+--------+
| CSV | --c2c,-c | --c2t | --c2j | --c2l | --c2d | --c2n | --c2x | --c2p | --c2m | --c2y |
| TSV | --t2c | --t2t,-t | --t2j | --t2l | --t2d | --t2n | --t2x | --t2p | --t2m | --t2y |
| JSON | --j2c | --j2t | --j2j,-j | --j2l | --j2d | --j2n | --j2x | --j2p | --j2m | --j2y |
| JSONL | --l2c | --l2t | --l2j | --l2l | --l2d | --l2n | --l2x | --l2p | --l2m | --l2y |
| DKVP | --d2c | --d2t | --d2j | --d2l | --d2d | --d2n | --d2x | --d2p | --d2m | --d2y |
| NIDX | --n2c | --n2t | --n2j | --n2l | --n2d | --n2n | --n2x | --n2p | --n2m | --n2y |
| XTAB | --x2c | --x2t | --x2j | --x2l | --x2d | --x2n | --x2x | --x2p | --x2m | --x2y |
| PPRINT | --p2c | --p2t | --p2j | --p2l | --p2d | --p2n | --p2x | -p2p | --p2m | --p2y |
| Markdown | --m2c | --m2t | --m2j | --m2l | --m2d | --m2n | --m2x | --m2p | | --m2y |
| YAML | --y2c | --y2t | --y2j | --y2l | --y2d | --y2n | --y2x | --y2p | --y2m | --y2y |
-p Keystroke-saver for `--nidx --fs space --repifs`.
-T Keystroke-saver for `--nidx --fs tab`.
@ -467,6 +481,10 @@
the default for JSON Lines output format.
--no-jvstack Put objects/arrays all on one line for JSON output.
This is the default for JSON Lines output format.
--no-yarray Do not wrap YAML output in a single array document;
emit one YAML document per record with `---` between.
--yarray or --ya Wrap YAML output in a single top-level array
document. This is the default for YAML output format.
1mLEGACY FLAGS0m
These are flags which don't do anything in the current Miller version.
@ -806,6 +824,7 @@
pprint " " N/A "\n"
tsv " " N/A "\n"
xtab "\n" " " "\n\n"
yaml N/A N/A N/A
--fs {string} Specify FS for input and output.
--ifs {string} Specify FS for input.

View file

@ -104,6 +104,16 @@ JSON Lines (sequence of one-line objects):
Record 1: "apple":"1", "bat":"2", "cog":"3"
Record 2: "dish:egg":"7", "dish:flint":"8", "garlic":""
YAML (single document = object or array of objects; multiple documents with ---):
+---------------------+
| apple: 1 |
| bat: 2 | Record 1: "apple":"1", "bat":"2", "cog":"3"
| cog: 3 |
| --- |
| dish: 7 | Record 2: "dish":"7", "egg":"8"
| egg: 8 |
+---------------------+
PPRINT: pretty-printed tabular
+---------------------+
| apple bat cog |
@ -475,6 +485,7 @@ are overridden in all cases by setting output format to `format2`.
--itsvlite Use TSV-lite format for input data.
--iusv or --iusvlite Use USV format for input data.
--ixtab Use XTAB format for input data.
--iyaml Use YAML format for input data.
--json or -j or --j2j Use JSON format for input and output data.
--jsonl or --l2l Use JSON Lines format for input and output data.
--nidx or --n2n Use NIDX format for input and output data.
@ -491,12 +502,14 @@ are overridden in all cases by setting output format to `format2`.
--otsvlite Use TSV-lite format for output data.
--ousv or --ousvlite Use USV format for output data.
--oxtab Use XTAB format for output data.
--oyaml Use YAML format for output data.
--pprint or --p2p Use PPRINT format for input and output data.
--tsv or -t or --t2t Use TSV format for input and output data.
--tsvlite Use TSV-lite format for input and output data.
--usv or --usvlite Use USV format for input and output data.
--xtab or --x2x Use XTAB format for input and output data.
--xvright Right-justify values for XTAB format.
--yaml or --y2y Use YAML format for input and output data.
-i {format name} Use format name for input data. For example: `-i csv`
is the same as `--icsv`.
-o {format name} Use format name for output data. For example: `-o
@ -540,20 +553,21 @@ See the flatten/unflatten doc page https://miller.readthedocs.io/en/latest/flatt
.\}
.nf
As keystroke-savers for format-conversion you may use the following.
The letters c, t, j, l, d, n, x, p, and m refer to formats CSV, TSV, DKVP, NIDX,
JSON, JSON Lines, XTAB, PPRINT, and markdown, respectively.
The letters c, t, j, l, d, n, x, p, m, and y refer to formats CSV, TSV, JSON, JSON Lines,
DKVP, NIDX, XTAB, PPRINT, markdown, and YAML, respectively.
| In\eout | CSV | TSV | JSON | JSONL | DKVP | NIDX | XTAB | PPRINT | Markdown |
+----------+----------+----------+----------+-------+-------+-------+-------+--------+----------|
| CSV | --c2c,-c | --c2t | --c2j | --c2l | --c2d | --c2n | --c2x | --c2p | --c2m |
| TSV | --t2c | --t2t,-t | --t2j | --t2l | --t2d | --t2n | --t2x | --t2p | --t2m |
| JSON | --j2c | --j2t | --j2j,-j | --j2l | --j2d | --j2n | --j2x | --j2p | --j2m |
| JSONL | --l2c | --l2t | --l2j | --l2l | --l2d | --l2n | --l2x | --l2p | --l2m |
| DKVP | --d2c | --d2t | --d2j | --d2l | --d2d | --d2n | --d2x | --d2p | --d2m |
| NIDX | --n2c | --n2t | --n2j | --n2l | --n2d | --n2n | --n2x | --n2p | --n2m |
| XTAB | --x2c | --x2t | --x2j | --x2l | --x2d | --x2n | --x2x | --x2p | --x2m |
| PPRINT | --p2c | --p2t | --p2j | --p2l | --p2d | --p2n | --p2x | -p2p | --p2m |
| Markdown | --m2c | --m2t | --m2j | --m2l | --m2d | --m2n | --m2x | --m2p | |
| In\eout | CSV | TSV | JSON | JSONL | DKVP | NIDX | XTAB | PPRINT | Markdown | YAML |
+----------+----------+----------+----------+-------+-------+-------+-------+--------+----------+--------+
| CSV | --c2c,-c | --c2t | --c2j | --c2l | --c2d | --c2n | --c2x | --c2p | --c2m | --c2y |
| TSV | --t2c | --t2t,-t | --t2j | --t2l | --t2d | --t2n | --t2x | --t2p | --t2m | --t2y |
| JSON | --j2c | --j2t | --j2j,-j | --j2l | --j2d | --j2n | --j2x | --j2p | --j2m | --j2y |
| JSONL | --l2c | --l2t | --l2j | --l2l | --l2d | --l2n | --l2x | --l2p | --l2m | --l2y |
| DKVP | --d2c | --d2t | --d2j | --d2l | --d2d | --d2n | --d2x | --d2p | --d2m | --d2y |
| NIDX | --n2c | --n2t | --n2j | --n2l | --n2d | --n2n | --n2x | --n2p | --n2m | --n2y |
| XTAB | --x2c | --x2t | --x2j | --x2l | --x2d | --x2n | --x2x | --x2p | --x2m | --x2y |
| PPRINT | --p2c | --p2t | --p2j | --p2l | --p2d | --p2n | --p2x | -p2p | --p2m | --p2y |
| Markdown | --m2c | --m2t | --m2j | --m2l | --m2d | --m2n | --m2x | --m2p | | --m2y |
| YAML | --y2c | --y2t | --y2j | --y2l | --y2d | --y2n | --y2x | --y2p | --y2m | --y2y |
-p Keystroke-saver for `--nidx --fs space --repifs`.
-T Keystroke-saver for `--nidx --fs tab`.
@ -580,6 +594,10 @@ These are flags which are applicable to JSON output format.
the default for JSON Lines output format.
--no-jvstack Put objects/arrays all on one line for JSON output.
This is the default for JSON Lines output format.
--no-yarray Do not wrap YAML output in a single array document;
emit one YAML document per record with `---` between.
--yarray or --ya Wrap YAML output in a single top-level array
document. This is the default for YAML output format.
.fi
.if n \{\
.RE
@ -967,6 +985,7 @@ Notes about all other separators:
pprint " " N/A "\en"
tsv " " N/A "\en"
xtab "\en" " " "\en\en"
yaml N/A N/A N/A
--fs {string} Specify FS for input and output.
--ifs {string} Specify FS for input.

View file

@ -468,6 +468,24 @@ var JSONOnlyFlagSection = FlagSection{
},
},
{
name: "--yarray",
altNames: []string{"--ya"},
help: "Wrap YAML output in a single top-level array document. This is the default for YAML output format.",
parser: func(args []string, argc int, pargi *int, options *TOptions) {
options.WriterOptions.WrapYAMLOutputInOuterList = true
*pargi += 1
},
},
{
name: "--no-yarray",
help: "Do not wrap YAML output in a single array document; emit one YAML document per record with `---` between.",
parser: func(args []string, argc int, pargi *int, options *TOptions) {
options.WriterOptions.WrapYAMLOutputInOuterList = false
*pargi += 1
},
},
{
name: "--jvquoteall",
help: "Force all JSON values -- recursively into lists and object -- to string.",
@ -760,6 +778,15 @@ var FileFormatFlagSection = FlagSection{
},
},
{
name: "--iyaml",
help: "Use YAML format for input data.",
parser: func(args []string, argc int, pargi *int, options *TOptions) {
options.ReaderOptions.InputFileFormat = "yaml"
*pargi += 1
},
},
{
name: "--inidx",
help: "Use NIDX format for input data.",
@ -984,6 +1011,16 @@ var FileFormatFlagSection = FlagSection{
},
},
{
name: "--oyaml",
help: "Use YAML format for output data.",
parser: func(args []string, argc int, pargi *int, options *TOptions) {
options.WriterOptions.OutputFileFormat = "yaml"
options.WriterOptions.WrapYAMLOutputInOuterList = true
*pargi += 1
},
},
{
name: "--onidx",
help: "Use NIDX format for output data.",
@ -1151,6 +1188,18 @@ var FileFormatFlagSection = FlagSection{
},
},
{
name: "--yaml",
help: "Use YAML format for input and output data.",
altNames: []string{"--y2y"},
parser: func(args []string, argc int, pargi *int, options *TOptions) {
options.ReaderOptions.InputFileFormat = "yaml"
options.WriterOptions.OutputFileFormat = "yaml"
options.WriterOptions.WrapYAMLOutputInOuterList = true
*pargi += 1
},
},
{
name: "--nidx",
help: "Use NIDX format for input and output data.",
@ -1202,20 +1251,21 @@ var FileFormatFlagSection = FlagSection{
func FormatConversionKeystrokeSaverPrintInfo() {
fmt.Println(`As keystroke-savers for format-conversion you may use the following.
The letters c, t, j, l, d, n, x, p, and m refer to formats CSV, TSV, DKVP, NIDX,
JSON, JSON Lines, XTAB, PPRINT, and markdown, respectively.
The letters c, t, j, l, d, n, x, p, m, and y refer to formats CSV, TSV, JSON, JSON Lines,
DKVP, NIDX, XTAB, PPRINT, markdown, and YAML, respectively.
| In\out | CSV | TSV | JSON | JSONL | DKVP | NIDX | XTAB | PPRINT | Markdown |
+----------+----------+----------+----------+-------+-------+-------+-------+--------+----------|
| CSV | --c2c,-c | --c2t | --c2j | --c2l | --c2d | --c2n | --c2x | --c2p | --c2m |
| TSV | --t2c | --t2t,-t | --t2j | --t2l | --t2d | --t2n | --t2x | --t2p | --t2m |
| JSON | --j2c | --j2t | --j2j,-j | --j2l | --j2d | --j2n | --j2x | --j2p | --j2m |
| JSONL | --l2c | --l2t | --l2j | --l2l | --l2d | --l2n | --l2x | --l2p | --l2m |
| DKVP | --d2c | --d2t | --d2j | --d2l | --d2d | --d2n | --d2x | --d2p | --d2m |
| NIDX | --n2c | --n2t | --n2j | --n2l | --n2d | --n2n | --n2x | --n2p | --n2m |
| XTAB | --x2c | --x2t | --x2j | --x2l | --x2d | --x2n | --x2x | --x2p | --x2m |
| PPRINT | --p2c | --p2t | --p2j | --p2l | --p2d | --p2n | --p2x | -p2p | --p2m |
| Markdown | --m2c | --m2t | --m2j | --m2l | --m2d | --m2n | --m2x | --m2p | |`)
| In\out | CSV | TSV | JSON | JSONL | DKVP | NIDX | XTAB | PPRINT | Markdown | YAML |
+----------+----------+----------+----------+-------+-------+-------+-------+--------+----------+--------+
| CSV | --c2c,-c | --c2t | --c2j | --c2l | --c2d | --c2n | --c2x | --c2p | --c2m | --c2y |
| TSV | --t2c | --t2t,-t | --t2j | --t2l | --t2d | --t2n | --t2x | --t2p | --t2m | --t2y |
| JSON | --j2c | --j2t | --j2j,-j | --j2l | --j2d | --j2n | --j2x | --j2p | --j2m | --j2y |
| JSONL | --l2c | --l2t | --l2j | --l2l | --l2d | --l2n | --l2x | --l2p | --l2m | --l2y |
| DKVP | --d2c | --d2t | --d2j | --d2l | --d2d | --d2n | --d2x | --d2p | --d2m | --d2y |
| NIDX | --n2c | --n2t | --n2j | --n2l | --n2d | --n2n | --n2x | --n2p | --n2m | --n2y |
| XTAB | --x2c | --x2t | --x2j | --x2l | --x2d | --x2n | --x2x | --x2p | --x2m | --x2y |
| PPRINT | --p2c | --p2t | --p2j | --p2l | --p2d | --p2n | --p2x | -p2p | --p2m | --p2y |
| Markdown | --m2c | --m2t | --m2j | --m2l | --m2d | --m2n | --m2x | --m2p | | --m2y |
| YAML | --y2c | --y2t | --y2j | --y2l | --y2d | --y2n | --y2x | --y2p | --y2m | --y2y |`)
}
func init() { FormatConversionKeystrokeSaverFlagSection.Sort() }
@ -1352,6 +1402,18 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{
*pargi += 1
},
},
{
name: "--c2y",
help: "Use CSV for input, YAML for output.",
suppressFlagEnumeration: true,
parser: func(args []string, argc int, pargi *int, options *TOptions) {
options.ReaderOptions.InputFileFormat = "csv"
options.WriterOptions.OutputFileFormat = "yaml"
options.WriterOptions.WrapYAMLOutputInOuterList = true
options.ReaderOptions.irsWasSpecified = true
*pargi += 1
},
},
{
name: "--c2b",
help: "Use CSV for input, PPRINT with `--barred` for output.",
@ -1484,6 +1546,17 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{
*pargi += 1
},
},
{
name: "--t2y",
help: "Use TSV for input, YAML for output.",
suppressFlagEnumeration: true,
parser: func(args []string, argc int, pargi *int, options *TOptions) {
options.ReaderOptions.InputFileFormat = "tsv"
options.WriterOptions.OutputFileFormat = "yaml"
options.WriterOptions.WrapYAMLOutputInOuterList = true
*pargi += 1
},
},
{
name: "--t2b",
help: "Use TSV for input, PPRINT with `--barred` for output.",
@ -1615,6 +1688,17 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{
*pargi += 1
},
},
{
name: "--d2y",
help: "Use DKVP for input, YAML for output.",
suppressFlagEnumeration: true,
parser: func(args []string, argc int, pargi *int, options *TOptions) {
options.ReaderOptions.InputFileFormat = "dkvp"
options.WriterOptions.OutputFileFormat = "yaml"
options.WriterOptions.WrapYAMLOutputInOuterList = true
*pargi += 1
},
},
{
name: "--d2b",
help: "Use DKVP for input, PPRINT with `--barred` for output.",
@ -1742,6 +1826,17 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{
*pargi += 1
},
},
{
name: "--n2y",
help: "Use NIDX for input, YAML for output.",
suppressFlagEnumeration: true,
parser: func(args []string, argc int, pargi *int, options *TOptions) {
options.ReaderOptions.InputFileFormat = "nidx"
options.WriterOptions.OutputFileFormat = "yaml"
options.WriterOptions.WrapYAMLOutputInOuterList = true
*pargi += 1
},
},
{
name: "--n2b",
help: "Use NIDX for input, PPRINT with `--barred` for output.",
@ -1868,6 +1963,17 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{
*pargi += 1
},
},
{
name: "--j2y",
help: "Use JSON for input, YAML for output.",
suppressFlagEnumeration: true,
parser: func(args []string, argc int, pargi *int, options *TOptions) {
options.ReaderOptions.InputFileFormat = "json"
options.WriterOptions.OutputFileFormat = "yaml"
options.WriterOptions.WrapYAMLOutputInOuterList = true
*pargi += 1
},
},
{
name: "--j2b",
help: "Use JSON for input, PPRINT with --barred for output.",
@ -1991,6 +2097,17 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{
*pargi += 1
},
},
{
name: "--l2y",
help: "Use JSON Lines for input, YAML for output.",
suppressFlagEnumeration: true,
parser: func(args []string, argc int, pargi *int, options *TOptions) {
options.ReaderOptions.InputFileFormat = "json"
options.WriterOptions.OutputFileFormat = "yaml"
options.WriterOptions.WrapYAMLOutputInOuterList = true
*pargi += 1
},
},
{
name: "--l2b",
help: "Use JSON Lines for input, PPRINT with --barred for output.",
@ -2146,6 +2263,19 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{
*pargi += 1
},
},
{
name: "--p2y",
help: "Use PPRINT for input, YAML for output.",
suppressFlagEnumeration: true,
parser: func(args []string, argc int, pargi *int, options *TOptions) {
options.ReaderOptions.InputFileFormat = "pprint"
options.ReaderOptions.IFS = " "
options.WriterOptions.OutputFileFormat = "yaml"
options.WriterOptions.WrapYAMLOutputInOuterList = true
options.ReaderOptions.ifsWasSpecified = true
*pargi += 1
},
},
{
name: "--m2c",
@ -2255,6 +2385,123 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{
*pargi += 1
},
},
{
name: "--m2y",
help: "Use markdown-tabular for input, YAML for output.",
suppressFlagEnumeration: true,
parser: func(args []string, argc int, pargi *int, options *TOptions) {
options.ReaderOptions.InputFileFormat = "markdown"
options.WriterOptions.OutputFileFormat = "yaml"
options.WriterOptions.WrapYAMLOutputInOuterList = true
options.ReaderOptions.ifsWasSpecified = true
*pargi += 1
},
},
{
name: "--y2c",
help: "Use YAML for input, CSV for output.",
suppressFlagEnumeration: true,
parser: func(args []string, argc int, pargi *int, options *TOptions) {
options.ReaderOptions.InputFileFormat = "yaml"
options.WriterOptions.OutputFileFormat = "csv"
options.WriterOptions.orsWasSpecified = true
*pargi += 1
},
},
{
name: "--y2t",
help: "Use YAML for input, TSV for output.",
suppressFlagEnumeration: true,
parser: func(args []string, argc int, pargi *int, options *TOptions) {
options.ReaderOptions.InputFileFormat = "yaml"
options.WriterOptions.OutputFileFormat = "tsv"
*pargi += 1
},
},
{
name: "--y2j",
help: "Use YAML for input, JSON for output.",
suppressFlagEnumeration: true,
parser: func(args []string, argc int, pargi *int, options *TOptions) {
options.ReaderOptions.InputFileFormat = "yaml"
options.WriterOptions.OutputFileFormat = "json"
options.WriterOptions.WrapJSONOutputInOuterList = true
options.WriterOptions.JSONOutputMultiline = true
*pargi += 1
},
},
{
name: "--y2l",
help: "Use YAML for input, JSON Lines for output.",
suppressFlagEnumeration: true,
parser: func(args []string, argc int, pargi *int, options *TOptions) {
options.ReaderOptions.InputFileFormat = "yaml"
options.WriterOptions.OutputFileFormat = "jsonl"
*pargi += 1
},
},
{
name: "--y2d",
help: "Use YAML for input, DKVP for output.",
suppressFlagEnumeration: true,
parser: func(args []string, argc int, pargi *int, options *TOptions) {
options.ReaderOptions.InputFileFormat = "yaml"
options.WriterOptions.OutputFileFormat = "dkvp"
*pargi += 1
},
},
{
name: "--y2n",
help: "Use YAML for input, NIDX for output.",
suppressFlagEnumeration: true,
parser: func(args []string, argc int, pargi *int, options *TOptions) {
options.ReaderOptions.InputFileFormat = "yaml"
options.WriterOptions.OutputFileFormat = "nidx"
*pargi += 1
},
},
{
name: "--y2x",
help: "Use YAML for input, XTAB for output.",
suppressFlagEnumeration: true,
parser: func(args []string, argc int, pargi *int, options *TOptions) {
options.ReaderOptions.InputFileFormat = "yaml"
options.WriterOptions.OutputFileFormat = "xtab"
*pargi += 1
},
},
{
name: "--y2p",
help: "Use YAML for input, PPRINT for output.",
suppressFlagEnumeration: true,
parser: func(args []string, argc int, pargi *int, options *TOptions) {
options.ReaderOptions.InputFileFormat = "yaml"
options.WriterOptions.OutputFileFormat = "pprint"
*pargi += 1
},
},
{
name: "--y2m",
help: "Use YAML for input, markdown-tabular for output.",
suppressFlagEnumeration: true,
parser: func(args []string, argc int, pargi *int, options *TOptions) {
options.ReaderOptions.InputFileFormat = "yaml"
options.WriterOptions.OutputFileFormat = "markdown"
*pargi += 1
},
},
{
name: "--y2y",
help: "Use YAML for input and output.",
suppressFlagEnumeration: true,
parser: func(args []string, argc int, pargi *int, options *TOptions) {
options.ReaderOptions.InputFileFormat = "yaml"
options.WriterOptions.OutputFileFormat = "yaml"
options.WriterOptions.WrapYAMLOutputInOuterList = true
*pargi += 1
},
},
{
name: "--x2c",
@ -2357,6 +2604,17 @@ var FormatConversionKeystrokeSaverFlagSection = FlagSection{
*pargi += 1
},
},
{
name: "--x2y",
help: "Use XTAB for input, YAML for output.",
suppressFlagEnumeration: true,
parser: func(args []string, argc int, pargi *int, options *TOptions) {
options.ReaderOptions.InputFileFormat = "xtab"
options.WriterOptions.OutputFileFormat = "yaml"
options.WriterOptions.WrapYAMLOutputInOuterList = true
*pargi += 1
},
},
{
name: "--x2b",
help: "Use XTAB for input, PPRINT with `--barred` for output.",

View file

@ -109,6 +109,9 @@ type TWriterOptions struct {
JVQuoteAll bool // --jvquoteall
// Not using miller/types enum to avoid package cycle
// YAML output: wrap in outer list (single document array) vs one document per record
WrapYAMLOutputInOuterList bool
CSVQuoteAll bool // --quote-all
// When we read things like
@ -253,6 +256,7 @@ func DefaultWriterOptions() TWriterOptions {
WrapJSONOutputInOuterList: true,
JSONOutputMultiline: true,
WrapYAMLOutputInOuterList: true,
AutoUnflatten: true,
AutoFlatten: true,

View file

@ -87,6 +87,7 @@ var defaultFSes = map[string]string{
"csvlite": ",",
"dkvp": ",",
"json": "N/A", // not alterable; not parameterizable in JSON format
"yaml": "N/A",
"nidx": " ",
"markdown": " ",
"pprint": " ",
@ -100,6 +101,7 @@ var defaultPSes = map[string]string{
"csvlite": "N/A",
"dkvp": "=",
"json": "N/A", // not alterable; not parameterizable in JSON format
"yaml": "N/A",
"markdown": "N/A",
"nidx": "N/A",
"pprint": "N/A",
@ -113,6 +115,7 @@ var defaultRSes = map[string]string{
"csvlite": "\n",
"dkvp": "\n",
"json": "N/A", // not alterable; not parameterizable in JSON format
"yaml": "N/A",
"markdown": "\n",
"nidx": "\n",
"pprint": "\n",
@ -126,6 +129,7 @@ var defaultAllowRepeatIFSes = map[string]bool{
"csvlite": false,
"dkvp": false,
"json": false,
"yaml": false,
"markdown": false,
"nidx": false,
"pprint": true,

View file

@ -16,6 +16,8 @@ func Create(readerOptions *cli.TReaderOptions, recordsPerBatch int64) (IRecordRe
return NewRecordReaderDKVP(readerOptions, recordsPerBatch)
case "json":
return NewRecordReaderJSON(readerOptions, recordsPerBatch)
case "yaml":
return NewRecordReaderYAML(readerOptions, recordsPerBatch)
case "nidx":
return NewRecordReaderNIDX(readerOptions, recordsPerBatch)
case "md":

View file

@ -0,0 +1,153 @@
package input
import (
"fmt"
"io"
"gopkg.in/yaml.v3"
"github.com/johnkerl/miller/v6/pkg/cli"
"github.com/johnkerl/miller/v6/pkg/lib"
"github.com/johnkerl/miller/v6/pkg/mlrval"
"github.com/johnkerl/miller/v6/pkg/types"
)
type RecordReaderYAML struct {
readerOptions *cli.TReaderOptions
recordsPerBatch int64
}
func NewRecordReaderYAML(
readerOptions *cli.TReaderOptions,
recordsPerBatch int64,
) (*RecordReaderYAML, error) {
return &RecordReaderYAML{
readerOptions: readerOptions,
recordsPerBatch: recordsPerBatch,
}, nil
}
func (reader *RecordReaderYAML) Read(
filenames []string,
context types.Context,
readerChannel chan<- []*types.RecordAndContext,
errorChannel chan error,
downstreamDoneChannel <-chan bool,
) {
if filenames != nil {
if len(filenames) == 0 {
handle, err := lib.OpenStdin(
reader.readerOptions.Prepipe,
reader.readerOptions.PrepipeIsRaw,
reader.readerOptions.FileInputEncoding,
)
if err != nil {
errorChannel <- err
} else {
reader.processHandle(handle, "(stdin)", &context, readerChannel, errorChannel, downstreamDoneChannel)
}
} else {
for _, filename := range filenames {
handle, err := lib.OpenFileForRead(
filename,
reader.readerOptions.Prepipe,
reader.readerOptions.PrepipeIsRaw,
reader.readerOptions.FileInputEncoding,
)
if err != nil {
errorChannel <- err
} else {
reader.processHandle(handle, filename, &context, readerChannel, errorChannel, downstreamDoneChannel)
handle.Close()
}
}
}
}
readerChannel <- types.NewEndOfStreamMarkerList(&context)
}
func (reader *RecordReaderYAML) processHandle(
handle io.Reader,
filename string,
context *types.Context,
readerChannel chan<- []*types.RecordAndContext,
errorChannel chan error,
downstreamDoneChannel <-chan bool,
) {
context.UpdateForStartOfFile(filename)
recordsPerBatch := reader.recordsPerBatch
decoder := yaml.NewDecoder(handle)
recordsAndContexts := make([]*types.RecordAndContext, 0, recordsPerBatch)
i := int64(0)
for {
i++
if i%recordsPerBatch == 0 {
select {
case <-downstreamDoneChannel:
goto flush
default:
}
}
mlrval, eof, err := mlrval.MlrvalDecodeFromYAML(decoder)
if eof {
break
}
if err != nil {
errorChannel <- err
return
}
if mlrval.IsMap() {
record := mlrval.GetMap()
if record == nil {
errorChannel <- fmt.Errorf("internal coding error in YAML record-reader")
return
}
context.UpdateForInputRecord()
recordsAndContexts = append(recordsAndContexts, types.NewRecordAndContext(record, context))
if int64(len(recordsAndContexts)) >= recordsPerBatch {
readerChannel <- recordsAndContexts
recordsAndContexts = make([]*types.RecordAndContext, 0, recordsPerBatch)
}
} else if mlrval.IsArray() {
records := mlrval.GetArray()
if records == nil {
errorChannel <- fmt.Errorf("internal coding error in YAML record-reader")
return
}
for _, mv := range records {
if !mv.IsMap() {
errorChannel <- fmt.Errorf(
"valid but unmillerable YAML: expected map (object); got %s",
mv.GetTypeName(),
)
return
}
record := mv.GetMap()
if record == nil {
errorChannel <- fmt.Errorf("internal coding error in YAML record-reader")
return
}
context.UpdateForInputRecord()
recordsAndContexts = append(recordsAndContexts, types.NewRecordAndContext(record, context))
if int64(len(recordsAndContexts)) >= recordsPerBatch {
readerChannel <- recordsAndContexts
recordsAndContexts = make([]*types.RecordAndContext, 0, recordsPerBatch)
}
}
} else {
errorChannel <- fmt.Errorf(
"valid but unmillerable YAML: expected map (object); got %s",
mlrval.GetTypeName(),
)
return
}
}
flush:
if len(recordsAndContexts) > 0 {
readerChannel <- recordsAndContexts
}
}

202
pkg/mlrval/mlrval_yaml.go Normal file
View file

@ -0,0 +1,202 @@
// ================================================================
// YAML decode/encode for Mlrval and Mlrmap.
// Converts between YAML native types (from gopkg.in/yaml.v3) and Miller's
// record model. YAML maps become Mlrmap; keys are stringified (YAML allows
// non-string keys). Used by the YAML record reader and writer.
// ================================================================
package mlrval
import (
"fmt"
"io"
"sort"
"gopkg.in/yaml.v3"
)
// MlrvalDecodeFromYAML decodes one YAML document from the decoder into an
// *Mlrval. Returns (nil, true, nil) on EOF. The decoded value can be a map
// (one record), array (array of records when elements are maps), or scalar.
func MlrvalDecodeFromYAML(decoder *yaml.Decoder) (*Mlrval, bool, error) {
var doc interface{}
err := decoder.Decode(&doc)
if err == io.EOF {
return nil, true, nil
}
if err != nil {
return nil, false, err
}
if doc == nil {
return NULL, false, nil
}
mv, err := mlrvalFromYAMLNative(doc)
if err != nil {
return nil, false, err
}
return mv, false, nil
}
// mlrvalFromYAMLNative converts a YAML-decoded value (map[interface{}]interface{},
// []interface{}, or scalar) into *Mlrval.
func mlrvalFromYAMLNative(v interface{}) (*Mlrval, error) {
if v == nil {
return NULL, nil
}
switch val := v.(type) {
case map[interface{}]interface{}:
return mlrvalFromYAMLMap(val)
case map[string]interface{}:
return mlrvalFromYAMLStringMap(val)
case []interface{}:
return mlrvalFromYAMLArray(val)
case string:
return FromString(val), nil
case bool:
return FromBool(val), nil
case int:
return FromInt(int64(val)), nil
case int64:
return FromInt(val), nil
case uint64:
if val <= 1<<63-1 {
return FromInt(int64(val)), nil
}
return FromFloat(float64(val)), nil
case float64:
return FromFloat(val), nil
case float32:
return FromFloat(float64(val)), nil
default:
return FromString(fmt.Sprint(val)), nil
}
}
func mlrvalFromYAMLMap(m map[interface{}]interface{}) (*Mlrval, error) {
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, yamlKeyString(k))
}
sort.Strings(keys)
out := FromEmptyMap()
for _, keyStr := range keys {
var v interface{}
for k, val := range m {
if yamlKeyString(k) == keyStr {
v = val
break
}
}
valMv, err := mlrvalFromYAMLNative(v)
if err != nil {
return nil, err
}
out.MapPut(FromString(keyStr), valMv)
}
return out, nil
}
func mlrvalFromYAMLStringMap(m map[string]interface{}) (*Mlrval, error) {
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
out := FromEmptyMap()
for _, k := range keys {
valMv, err := mlrvalFromYAMLNative(m[k])
if err != nil {
return nil, err
}
out.MapPut(FromString(k), valMv)
}
return out, nil
}
func yamlKeyString(k interface{}) string {
switch t := k.(type) {
case string:
return t
case int:
return fmt.Sprintf("%d", t)
case int64:
return fmt.Sprintf("%d", t)
case float64:
return fmt.Sprintf("%g", t)
default:
return fmt.Sprint(k)
}
}
func mlrvalFromYAMLArray(a []interface{}) (*Mlrval, error) {
out := FromEmptyArray()
for _, elem := range a {
mv, err := mlrvalFromYAMLNative(elem)
if err != nil {
return nil, err
}
out.ArrayAppend(mv)
}
return out, nil
}
// MlrmapToYAMLNative converts an Mlrmap to a Go value suitable for
// yaml.Marshal: map[string]interface{} with nested maps/arrays.
func MlrmapToYAMLNative(mlrmap *Mlrmap) (interface{}, error) {
if mlrmap == nil {
return nil, nil
}
out := make(map[string]interface{})
for pe := mlrmap.Head; pe != nil; pe = pe.Next {
v, err := mlrvalToYAMLNative(pe.Value)
if err != nil {
return nil, err
}
out[pe.Key] = v
}
return out, nil
}
// mlrvalToYAMLNative converts *Mlrval to a Go value for yaml.Marshal.
func mlrvalToYAMLNative(mv *Mlrval) (interface{}, error) {
if mv == nil {
return nil, nil
}
switch mv.Type() {
case MT_ABSENT, MT_VOID, MT_NULL:
return nil, nil
case MT_STRING:
s, _ := mv.GetStringValue()
return s, nil
case MT_INT:
i, _ := mv.GetIntValue()
return i, nil
case MT_FLOAT:
f, _ := mv.GetFloatValue()
return f, nil
case MT_BOOL:
b, _ := mv.GetBoolValue()
return b, nil
case MT_ARRAY:
arr := mv.GetArray()
if arr == nil {
return []interface{}{}, nil
}
out := make([]interface{}, 0, len(arr))
for _, elem := range arr {
v, err := mlrvalToYAMLNative(elem)
if err != nil {
return nil, err
}
out = append(out, v)
}
return out, nil
case MT_MAP:
m := mv.GetMap()
return MlrmapToYAMLNative(m)
case MT_ERROR, MT_PENDING:
return mv.String(), nil
default:
return mv.String(), nil
}
}

View file

@ -0,0 +1,196 @@
// ================================================================
// Tests for YAML decode/encode (MlrvalDecodeFromYAML, MlrmapToYAMLNative).
// ================================================================
package mlrval
import (
"bytes"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3"
)
func TestMlrvalFromYAMLNativeScalars(t *testing.T) {
mv, err := mlrvalFromYAMLNative("hello")
assert.NoError(t, err)
assert.True(t, mv.IsString())
s, _ := mv.GetStringValue()
assert.Equal(t, "hello", s)
mv, err = mlrvalFromYAMLNative(42)
assert.NoError(t, err)
assert.True(t, mv.IsInt())
i, _ := mv.GetIntValue()
assert.Equal(t, int64(42), i)
mv, err = mlrvalFromYAMLNative(3.14)
assert.NoError(t, err)
assert.True(t, mv.IsFloat())
f, _ := mv.GetFloatValue()
assert.Equal(t, 3.14, f)
mv, err = mlrvalFromYAMLNative(true)
assert.NoError(t, err)
assert.True(t, mv.IsBool())
b, _ := mv.GetBoolValue()
assert.True(t, b)
mv, err = mlrvalFromYAMLNative(nil)
assert.NoError(t, err)
assert.True(t, mv.IsNull())
}
func TestMlrvalFromYAMLNativeMap(t *testing.T) {
// gopkg.in/yaml.v3 unmarshals into map[string]interface{}
m := map[string]interface{}{
"a": 1,
"b": "two",
"c": true,
}
mv, err := mlrvalFromYAMLNative(m)
assert.NoError(t, err)
assert.True(t, mv.IsMap())
rec := mv.GetMap()
assert.NotNil(t, rec)
assert.Equal(t, int64(3), rec.FieldCount)
av := rec.Get("a")
assert.True(t, av.IsInt())
ai, _ := av.GetIntValue()
assert.Equal(t, int64(1), ai)
bv := rec.Get("b")
assert.True(t, bv.IsString())
bs, _ := bv.GetStringValue()
assert.Equal(t, "two", bs)
}
func TestMlrvalDecodeFromYAML(t *testing.T) {
input := "a: 1\nb: 2\n"
decoder := yaml.NewDecoder(bytes.NewBufferString(input))
mv, eof, err := MlrvalDecodeFromYAML(decoder)
assert.NoError(t, err)
assert.False(t, eof)
assert.NotNil(t, mv)
assert.True(t, mv.IsMap())
rec := mv.GetMap()
assert.Equal(t, int64(2), rec.FieldCount)
v := rec.Get("a")
vi, _ := v.GetIntValue()
assert.Equal(t, int64(1), vi)
v = rec.Get("b")
vi, _ = v.GetIntValue()
assert.Equal(t, int64(2), vi)
// EOF on next decode
_, eof, err = MlrvalDecodeFromYAML(decoder)
assert.NoError(t, err)
assert.True(t, eof)
}
func TestMlrmapToYAMLNativeRoundTrip(t *testing.T) {
rec := NewMlrmapAsRecord()
rec.PutReference("x", FromInt(10))
rec.PutReference("y", FromString("hello"))
rec.PutReference("z", FromBool(true))
native, err := MlrmapToYAMLNative(rec)
assert.NoError(t, err)
assert.NotNil(t, native)
out, err := yaml.Marshal(native)
assert.NoError(t, err)
decoder := yaml.NewDecoder(bytes.NewReader(out))
mv, eof, err := MlrvalDecodeFromYAML(decoder)
assert.NoError(t, err)
assert.False(t, eof)
assert.True(t, mv.IsMap())
back := mv.GetMap()
xv := back.Get("x")
xi, _ := xv.GetIntValue()
assert.Equal(t, int64(10), xi)
yv := back.Get("y")
ys, _ := yv.GetStringValue()
assert.Equal(t, "hello", ys)
zv := back.Get("z")
zb, _ := zv.GetBoolValue()
assert.True(t, zb)
}
func TestMlrvalDecodeFromYAMLArrayOfMaps(t *testing.T) {
input := "- a: 1\n b: 2\n- a: 3\n b: 4\n"
decoder := yaml.NewDecoder(bytes.NewBufferString(input))
mv, eof, err := MlrvalDecodeFromYAML(decoder)
assert.NoError(t, err)
assert.False(t, eof)
assert.True(t, mv.IsArray())
arr := mv.GetArray()
assert.Len(t, arr, 2)
assert.True(t, arr[0].IsMap())
assert.True(t, arr[1].IsMap())
r0 := arr[0].GetMap()
av := r0.Get("a")
ai, _ := av.GetIntValue()
assert.Equal(t, int64(1), ai)
r1 := arr[1].GetMap()
av = r1.Get("a")
ai, _ = av.GetIntValue()
assert.Equal(t, int64(3), ai)
}
func TestMlrvalDecodeFromYAMLMultiDoc(t *testing.T) {
input := "a: 1\nb: 2\n---\nc: 3\nd: 4\n"
decoder := yaml.NewDecoder(bytes.NewBufferString(input))
mv1, eof, err := MlrvalDecodeFromYAML(decoder)
assert.NoError(t, err)
assert.False(t, eof)
assert.True(t, mv1.IsMap())
assert.Equal(t, int64(2), mv1.GetMap().FieldCount)
mv2, eof, err := MlrvalDecodeFromYAML(decoder)
assert.NoError(t, err)
assert.False(t, eof)
assert.True(t, mv2.IsMap())
assert.Equal(t, int64(2), mv2.GetMap().FieldCount)
_, eof, err = MlrvalDecodeFromYAML(decoder)
assert.NoError(t, err)
assert.True(t, eof)
}
func TestYAMLKeyStringNonStringKeys(t *testing.T) {
// map[interface{}]interface{} with int key
m := map[interface{}]interface{}{
1: "one",
"two": 2,
}
mv, err := mlrvalFromYAMLMap(m)
assert.NoError(t, err)
assert.True(t, mv.IsMap())
rec := mv.GetMap()
v := rec.Get("1")
assert.True(t, v.IsString())
s, _ := v.GetStringValue()
assert.Equal(t, "one", s)
v = rec.Get("two")
assert.True(t, v.IsInt())
}
func TestMlrmapToYAMLNativeNested(t *testing.T) {
inner := NewMlrmapAsRecord()
inner.PutReference("p", FromInt(1))
inner.PutReference("q", FromInt(2))
rec := NewMlrmapAsRecord()
rec.PutReference("a", FromString("x"))
rec.PutReference("nested", FromMap(inner))
native, err := MlrmapToYAMLNative(rec)
assert.NoError(t, err)
out, err := yaml.Marshal(native)
assert.NoError(t, err)
assert.True(t, strings.Contains(string(out), "nested:"))
assert.True(t, strings.Contains(string(out), "p: 1"))
}

View file

@ -18,6 +18,8 @@ func Create(writerOptions *cli.TWriterOptions) (IRecordWriter, error) {
return NewRecordWriterJSON(writerOptions)
case "jsonl":
return NewRecordWriterJSONLines(writerOptions)
case "yaml":
return NewRecordWriterYAML(writerOptions)
case "md":
return NewRecordWriterMarkdown(writerOptions)
case "markdown":

View file

@ -0,0 +1,91 @@
package output
import (
"bufio"
"fmt"
"os"
"gopkg.in/yaml.v3"
"github.com/johnkerl/miller/v6/pkg/cli"
"github.com/johnkerl/miller/v6/pkg/mlrval"
"github.com/johnkerl/miller/v6/pkg/types"
)
type RecordWriterYAML struct {
writerOptions *cli.TWriterOptions
bufferedRecords []interface{} // used when WrapYAMLOutputInOuterList is true
wroteAnyRecords bool // for multi-doc: emit "---\n" before 2nd and later docs
}
func NewRecordWriterYAML(writerOptions *cli.TWriterOptions) (*RecordWriterYAML, error) {
return &RecordWriterYAML{
writerOptions: writerOptions,
bufferedRecords: nil,
wroteAnyRecords: false,
}, nil
}
func (writer *RecordWriterYAML) Write(
outrec *mlrval.Mlrmap,
context *types.Context,
bufferedOutputStream *bufio.Writer,
outputIsStdout bool,
) error {
if writer.writerOptions.WrapYAMLOutputInOuterList {
writer.writeWithListWrap(outrec, bufferedOutputStream)
} else {
writer.writeWithoutListWrap(outrec, bufferedOutputStream)
}
return nil
}
func (writer *RecordWriterYAML) writeWithListWrap(
outrec *mlrval.Mlrmap,
bufferedOutputStream *bufio.Writer,
) {
if outrec != nil {
if writer.bufferedRecords == nil {
writer.bufferedRecords = make([]interface{}, 0)
}
native, err := mlrval.MlrmapToYAMLNative(outrec)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
writer.bufferedRecords = append(writer.bufferedRecords, native)
} else {
// End of stream: emit single YAML document as array
out, err := yaml.Marshal(writer.bufferedRecords)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
bufferedOutputStream.Write(out)
writer.bufferedRecords = nil
}
}
func (writer *RecordWriterYAML) writeWithoutListWrap(
outrec *mlrval.Mlrmap,
bufferedOutputStream *bufio.Writer,
) {
if outrec == nil {
return
}
if writer.wroteAnyRecords {
bufferedOutputStream.WriteString("---\n")
}
native, err := mlrval.MlrmapToYAMLNative(outrec)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
out, err := yaml.Marshal(native)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
bufferedOutputStream.Write(out)
writer.wroteAnyRecords = true
}

View file

@ -401,6 +401,16 @@ JSON Lines (sequence of one-line objects):
Record 1: "apple":"1", "bat":"2", "cog":"3"
Record 2: "dish:egg":"7", "dish:flint":"8", "garlic":""
YAML (single document = object or array of objects; multiple documents with ---):
+---------------------+
| apple: 1 |
| bat: 2 | Record 1: "apple":"1", "bat":"2", "cog":"3"
| cog: 3 |
| --- |
| dish: 7 | Record 2: "dish":"7", "egg":"8"
| egg: 8 |
+---------------------+
PPRINT: pretty-printed tabular
+---------------------+
| apple bat cog |

View file

@ -60,6 +60,7 @@ import (
"os"
"path/filepath"
"runtime"
"sort"
"strings"
"github.com/johnkerl/miller/v6/pkg/colorizer"
@ -167,6 +168,7 @@ func (regtester *RegTester) Execute(
regtester.resetCounts()
lib.InternalCodingErrorIf(len(casePaths) == 0)
sort.Strings(casePaths)
if !regtester.plainMode {
fmt.Println("REGRESSION TEST:")
@ -342,6 +344,7 @@ func (regtester *RegTester) hasCaseSubdirectories(
fmt.Printf("%s: %v\n", dirName, err)
os.Exit(1)
}
sort.Strings(names)
for _, name := range names {
path := dirName + string(filepath.Separator) + name

View file

@ -0,0 +1 @@
mlr --c2y cat test/input/abixy.csv

View file

@ -0,0 +1,50 @@
- a: pan
b: pan
i: 1
x: 0.3467901443380824
"y": 0.7268028627434533
- a: eks
b: pan
i: 2
x: 0.7586799647899636
"y": 0.5221511083334797
- a: wye
b: wye
i: 3
x: 0.20460330576630303
"y": 0.33831852551664776
- a: eks
b: wye
i: 4
x: 0.38139939387114097
"y": 0.13418874328430463
- a: wye
b: pan
i: 5
x: 0.5732889198020006
"y": 0.8636244699032729
- a: zee
b: pan
i: 6
x: 0.5271261600918548
"y": 0.49322128674835697
- a: eks
b: zee
i: 7
x: 0.6117840605678454
"y": 0.1878849191181694
- a: zee
b: wye
i: 8
x: 0.5985540091064224
"y": 0.976181385699006
- a: hat
b: wye
i: 9
x: 0.03144187646093577
"y": 0.7495507603507059
- a: pan
b: wye
i: 10
x: 0.5026260055412137
"y": 0.9526183602969864

View file

@ -0,0 +1 @@
mlr --d2y cat test/input/abixy.dkvp

View file

@ -0,0 +1,50 @@
- a: pan
b: pan
i: 1
x: 0.3467901443380824
"y": 0.7268028627434533
- a: eks
b: pan
i: 2
x: 0.7586799647899636
"y": 0.5221511083334797
- a: wye
b: wye
i: 3
x: 0.20460330576630303
"y": 0.33831852551664776
- a: eks
b: wye
i: 4
x: 0.38139939387114097
"y": 0.13418874328430463
- a: wye
b: pan
i: 5
x: 0.5732889198020006
"y": 0.8636244699032729
- a: zee
b: pan
i: 6
x: 0.5271261600918548
"y": 0.49322128674835697
- a: eks
b: zee
i: 7
x: 0.6117840605678454
"y": 0.1878849191181694
- a: zee
b: wye
i: 8
x: 0.5985540091064224
"y": 0.976181385699006
- a: hat
b: wye
i: 9
x: 0.03144187646093577
"y": 0.7495507603507059
- a: pan
b: wye
i: 10
x: 0.5026260055412137
"y": 0.9526183602969864

View file

@ -0,0 +1 @@
mlr --j2y cat test/input/abixy.json

View file

@ -0,0 +1,50 @@
- a: pan
b: pan
i: 1
x: 0.3467901443380824
"y": 0.7268028627434533
- a: eks
b: pan
i: 2
x: 0.7586799647899636
"y": 0.5221511083334797
- a: wye
b: wye
i: 3
x: 0.20460330576630303
"y": 0.33831852551664776
- a: eks
b: wye
i: 4
x: 0.38139939387114097
"y": 0.13418874328430463
- a: wye
b: pan
i: 5
x: 0.5732889198020006
"y": 0.8636244699032729
- a: zee
b: pan
i: 6
x: 0.5271261600918548
"y": 0.49322128674835697
- a: eks
b: zee
i: 7
x: 0.6117840605678454
"y": 0.1878849191181694
- a: zee
b: wye
i: 8
x: 0.5985540091064224
"y": 0.976181385699006
- a: hat
b: wye
i: 9
x: 0.03144187646093577
"y": 0.7495507603507059
- a: pan
b: wye
i: 10
x: 0.5026260055412137
"y": 0.9526183602969864

View file

@ -0,0 +1 @@
mlr --m2y cat test/input/abixy.md

View file

@ -0,0 +1,50 @@
- a: pan
b: pan
i: 1
x: 0.3467901443380824
"y": 0.7268028627434533
- a: eks
b: pan
i: 2
x: 0.7586799647899636
"y": 0.5221511083334797
- a: wye
b: wye
i: 3
x: 0.20460330576630303
"y": 0.33831852551664776
- a: eks
b: wye
i: 4
x: 0.38139939387114097
"y": 0.13418874328430463
- a: wye
b: pan
i: 5
x: 0.5732889198020006
"y": 0.8636244699032729
- a: zee
b: pan
i: 6
x: 0.5271261600918548
"y": 0.49322128674835697
- a: eks
b: zee
i: 7
x: 0.6117840605678454
"y": 0.1878849191181694
- a: zee
b: wye
i: 8
x: 0.5985540091064224
"y": 0.976181385699006
- a: hat
b: wye
i: 9
x: 0.03144187646093577
"y": 0.7495507603507059
- a: pan
b: wye
i: 10
x: 0.5026260055412137
"y": 0.9526183602969864

View file

@ -0,0 +1 @@
mlr --n2y cat test/input/abixy.nidx

View file

@ -0,0 +1,50 @@
- "1": pan
"2": pan
"3": 1
"4": 0.3467901443380824
"5": 0.7268028627434533
- "1": eks
"2": pan
"3": 2
"4": 0.7586799647899636
"5": 0.5221511083334797
- "1": wye
"2": wye
"3": 3
"4": 0.20460330576630303
"5": 0.33831852551664776
- "1": eks
"2": wye
"3": 4
"4": 0.38139939387114097
"5": 0.13418874328430463
- "1": wye
"2": pan
"3": 5
"4": 0.5732889198020006
"5": 0.8636244699032729
- "1": zee
"2": pan
"3": 6
"4": 0.5271261600918548
"5": 0.49322128674835697
- "1": eks
"2": zee
"3": 7
"4": 0.6117840605678454
"5": 0.1878849191181694
- "1": zee
"2": wye
"3": 8
"4": 0.5985540091064224
"5": 0.976181385699006
- "1": hat
"2": wye
"3": 9
"4": 0.03144187646093577
"5": 0.7495507603507059
- "1": pan
"2": wye
"3": 10
"4": 0.5026260055412137
"5": 0.9526183602969864

View file

@ -0,0 +1 @@
mlr --p2y cat test/input/abixy.pprint

View file

@ -0,0 +1,50 @@
- a: pan
b: pan
i: 1
x: 0.3467901443380824
"y": 0.7268028627434533
- a: eks
b: pan
i: 2
x: 0.7586799647899636
"y": 0.5221511083334797
- a: wye
b: wye
i: 3
x: 0.20460330576630303
"y": 0.33831852551664776
- a: eks
b: wye
i: 4
x: 0.38139939387114097
"y": 0.13418874328430463
- a: wye
b: pan
i: 5
x: 0.5732889198020006
"y": 0.8636244699032729
- a: zee
b: pan
i: 6
x: 0.5271261600918548
"y": 0.49322128674835697
- a: eks
b: zee
i: 7
x: 0.6117840605678454
"y": 0.1878849191181694
- a: zee
b: wye
i: 8
x: 0.5985540091064224
"y": 0.976181385699006
- a: hat
b: wye
i: 9
x: 0.03144187646093577
"y": 0.7495507603507059
- a: pan
b: wye
i: 10
x: 0.5026260055412137
"y": 0.9526183602969864

View file

@ -0,0 +1 @@
mlr --t2y cat test/input/abixy.tsv

View file

@ -0,0 +1,50 @@
- a: pan
b: pan
i: 1
x: 0.3467901443380824
"y": 0.7268028627434533
- a: eks
b: pan
i: 2
x: 0.7586799647899636
"y": 0.5221511083334797
- a: wye
b: wye
i: 3
x: 0.20460330576630303
"y": 0.33831852551664776
- a: eks
b: wye
i: 4
x: 0.38139939387114097
"y": 0.13418874328430463
- a: wye
b: pan
i: 5
x: 0.5732889198020006
"y": 0.8636244699032729
- a: zee
b: pan
i: 6
x: 0.5271261600918548
"y": 0.49322128674835697
- a: eks
b: zee
i: 7
x: 0.6117840605678454
"y": 0.1878849191181694
- a: zee
b: wye
i: 8
x: 0.5985540091064224
"y": 0.976181385699006
- a: hat
b: wye
i: 9
x: 0.03144187646093577
"y": 0.7495507603507059
- a: pan
b: wye
i: 10
x: 0.5026260055412137
"y": 0.9526183602969864

View file

@ -0,0 +1 @@
mlr --x2y cat test/input/abixy.xtab

View file

@ -0,0 +1,50 @@
- a: pan
b: pan
i: 1
x: 0.3467901443380824
"y": 0.7268028627434533
- a: eks
b: pan
i: 2
x: 0.7586799647899636
"y": 0.5221511083334797
- a: wye
b: wye
i: 3
x: 0.20460330576630303
"y": 0.33831852551664776
- a: eks
b: wye
i: 4
x: 0.38139939387114097
"y": 0.13418874328430463
- a: wye
b: pan
i: 5
x: 0.5732889198020006
"y": 0.8636244699032729
- a: zee
b: pan
i: 6
x: 0.5271261600918548
"y": 0.49322128674835697
- a: eks
b: zee
i: 7
x: 0.6117840605678454
"y": 0.1878849191181694
- a: zee
b: wye
i: 8
x: 0.5985540091064224
"y": 0.976181385699006
- a: hat
b: wye
i: 9
x: 0.03144187646093577
"y": 0.7495507603507059
- a: pan
b: wye
i: 10
x: 0.5026260055412137
"y": 0.9526183602969864

View file

@ -0,0 +1 @@
mlr --y2c cat ${CASEDIR}/input

View file

@ -0,0 +1,11 @@
a,b,i,x,y
pan,pan,1,0.34679014,0.72680286
eks,pan,2,0.75867996,0.52215111
wye,wye,3,0.20460331,0.33831853
eks,wye,4,0.38139939,0.13418874
wye,pan,5,0.57328892,0.86362447
zee,pan,6,0.52712616,0.49322129
eks,zee,7,0.61178406,0.18788492
zee,wye,8,0.59855401,0.97618139
hat,wye,9,0.03144188,0.74955076
pan,wye,10,0.50262601,0.95261836

View file

@ -0,0 +1,50 @@
- a: pan
b: pan
i: 1
x: 0.3467901443380824
"y": 0.7268028627434533
- a: eks
b: pan
i: 2
x: 0.7586799647899636
"y": 0.5221511083334797
- a: wye
b: wye
i: 3
x: 0.20460330576630303
"y": 0.33831852551664776
- a: eks
b: wye
i: 4
x: 0.38139939387114097
"y": 0.13418874328430463
- a: wye
b: pan
i: 5
x: 0.5732889198020006
"y": 0.8636244699032729
- a: zee
b: pan
i: 6
x: 0.5271261600918548
"y": 0.49322128674835697
- a: eks
b: zee
i: 7
x: 0.6117840605678454
"y": 0.1878849191181694
- a: zee
b: wye
i: 8
x: 0.5985540091064224
"y": 0.976181385699006
- a: hat
b: wye
i: 9
x: 0.03144187646093577
"y": 0.7495507603507059
- a: pan
b: wye
i: 10
x: 0.5026260055412137
"y": 0.9526183602969864

View file

@ -0,0 +1 @@
mlr --y2d cat ${CASEDIR}/input

View file

@ -0,0 +1,10 @@
a=pan,b=pan,i=1,x=0.34679014,y=0.72680286
a=eks,b=pan,i=2,x=0.75867996,y=0.52215111
a=wye,b=wye,i=3,x=0.20460331,y=0.33831853
a=eks,b=wye,i=4,x=0.38139939,y=0.13418874
a=wye,b=pan,i=5,x=0.57328892,y=0.86362447
a=zee,b=pan,i=6,x=0.52712616,y=0.49322129
a=eks,b=zee,i=7,x=0.61178406,y=0.18788492
a=zee,b=wye,i=8,x=0.59855401,y=0.97618139
a=hat,b=wye,i=9,x=0.03144188,y=0.74955076
a=pan,b=wye,i=10,x=0.50262601,y=0.95261836

View file

@ -0,0 +1,50 @@
- a: pan
b: pan
i: 1
x: 0.3467901443380824
"y": 0.7268028627434533
- a: eks
b: pan
i: 2
x: 0.7586799647899636
"y": 0.5221511083334797
- a: wye
b: wye
i: 3
x: 0.20460330576630303
"y": 0.33831852551664776
- a: eks
b: wye
i: 4
x: 0.38139939387114097
"y": 0.13418874328430463
- a: wye
b: pan
i: 5
x: 0.5732889198020006
"y": 0.8636244699032729
- a: zee
b: pan
i: 6
x: 0.5271261600918548
"y": 0.49322128674835697
- a: eks
b: zee
i: 7
x: 0.6117840605678454
"y": 0.1878849191181694
- a: zee
b: wye
i: 8
x: 0.5985540091064224
"y": 0.976181385699006
- a: hat
b: wye
i: 9
x: 0.03144187646093577
"y": 0.7495507603507059
- a: pan
b: wye
i: 10
x: 0.5026260055412137
"y": 0.9526183602969864

View file

@ -0,0 +1 @@
mlr --y2j cat ${CASEDIR}/input

View file

@ -0,0 +1,10 @@
[
{
"a": 1,
"b": 2
},
{
"a": 3,
"b": 4
}
]

View file

@ -0,0 +1,5 @@
a: 1
b: 2
---
a: 3
b: 4

View file

@ -0,0 +1 @@
mlr --y2m cat ${CASEDIR}/input

View file

@ -0,0 +1,12 @@
| a | b | i | x | y |
| --- | --- | --- | --- | --- |
| pan | pan | 1 | 0.34679014 | 0.72680286 |
| eks | pan | 2 | 0.75867996 | 0.52215111 |
| wye | wye | 3 | 0.20460331 | 0.33831853 |
| eks | wye | 4 | 0.38139939 | 0.13418874 |
| wye | pan | 5 | 0.57328892 | 0.86362447 |
| zee | pan | 6 | 0.52712616 | 0.49322129 |
| eks | zee | 7 | 0.61178406 | 0.18788492 |
| zee | wye | 8 | 0.59855401 | 0.97618139 |
| hat | wye | 9 | 0.03144188 | 0.74955076 |
| pan | wye | 10 | 0.50262601 | 0.95261836 |

View file

@ -0,0 +1,50 @@
- a: pan
b: pan
i: 1
x: 0.3467901443380824
"y": 0.7268028627434533
- a: eks
b: pan
i: 2
x: 0.7586799647899636
"y": 0.5221511083334797
- a: wye
b: wye
i: 3
x: 0.20460330576630303
"y": 0.33831852551664776
- a: eks
b: wye
i: 4
x: 0.38139939387114097
"y": 0.13418874328430463
- a: wye
b: pan
i: 5
x: 0.5732889198020006
"y": 0.8636244699032729
- a: zee
b: pan
i: 6
x: 0.5271261600918548
"y": 0.49322128674835697
- a: eks
b: zee
i: 7
x: 0.6117840605678454
"y": 0.1878849191181694
- a: zee
b: wye
i: 8
x: 0.5985540091064224
"y": 0.976181385699006
- a: hat
b: wye
i: 9
x: 0.03144187646093577
"y": 0.7495507603507059
- a: pan
b: wye
i: 10
x: 0.5026260055412137
"y": 0.9526183602969864

View file

@ -0,0 +1 @@
mlr --y2n cat ${CASEDIR}/input

View file

@ -0,0 +1,10 @@
pan pan 1 0.34679014 0.72680286
eks pan 2 0.75867996 0.52215111
wye wye 3 0.20460331 0.33831853
eks wye 4 0.38139939 0.13418874
wye pan 5 0.57328892 0.86362447
zee pan 6 0.52712616 0.49322129
eks zee 7 0.61178406 0.18788492
zee wye 8 0.59855401 0.97618139
hat wye 9 0.03144188 0.74955076
pan wye 10 0.50262601 0.95261836

View file

@ -0,0 +1,50 @@
- a: pan
b: pan
i: 1
x: 0.3467901443380824
"y": 0.7268028627434533
- a: eks
b: pan
i: 2
x: 0.7586799647899636
"y": 0.5221511083334797
- a: wye
b: wye
i: 3
x: 0.20460330576630303
"y": 0.33831852551664776
- a: eks
b: wye
i: 4
x: 0.38139939387114097
"y": 0.13418874328430463
- a: wye
b: pan
i: 5
x: 0.5732889198020006
"y": 0.8636244699032729
- a: zee
b: pan
i: 6
x: 0.5271261600918548
"y": 0.49322128674835697
- a: eks
b: zee
i: 7
x: 0.6117840605678454
"y": 0.1878849191181694
- a: zee
b: wye
i: 8
x: 0.5985540091064224
"y": 0.976181385699006
- a: hat
b: wye
i: 9
x: 0.03144187646093577
"y": 0.7495507603507059
- a: pan
b: wye
i: 10
x: 0.5026260055412137
"y": 0.9526183602969864

View file

@ -0,0 +1 @@
mlr --y2p cat ${CASEDIR}/input

View file

@ -0,0 +1,11 @@
a b i x y
pan pan 1 0.34679014 0.72680286
eks pan 2 0.75867996 0.52215111
wye wye 3 0.20460331 0.33831853
eks wye 4 0.38139939 0.13418874
wye pan 5 0.57328892 0.86362447
zee pan 6 0.52712616 0.49322129
eks zee 7 0.61178406 0.18788492
zee wye 8 0.59855401 0.97618139
hat wye 9 0.03144188 0.74955076
pan wye 10 0.50262601 0.95261836

View file

@ -0,0 +1,50 @@
- a: pan
b: pan
i: 1
x: 0.3467901443380824
"y": 0.7268028627434533
- a: eks
b: pan
i: 2
x: 0.7586799647899636
"y": 0.5221511083334797
- a: wye
b: wye
i: 3
x: 0.20460330576630303
"y": 0.33831852551664776
- a: eks
b: wye
i: 4
x: 0.38139939387114097
"y": 0.13418874328430463
- a: wye
b: pan
i: 5
x: 0.5732889198020006
"y": 0.8636244699032729
- a: zee
b: pan
i: 6
x: 0.5271261600918548
"y": 0.49322128674835697
- a: eks
b: zee
i: 7
x: 0.6117840605678454
"y": 0.1878849191181694
- a: zee
b: wye
i: 8
x: 0.5985540091064224
"y": 0.976181385699006
- a: hat
b: wye
i: 9
x: 0.03144187646093577
"y": 0.7495507603507059
- a: pan
b: wye
i: 10
x: 0.5026260055412137
"y": 0.9526183602969864

View file

@ -0,0 +1 @@
mlr --y2t cat ${CASEDIR}/input

View file

@ -0,0 +1,11 @@
a b i x y
pan pan 1 0.34679014 0.72680286
eks pan 2 0.75867996 0.52215111
wye wye 3 0.20460331 0.33831853
eks wye 4 0.38139939 0.13418874
wye pan 5 0.57328892 0.86362447
zee pan 6 0.52712616 0.49322129
eks zee 7 0.61178406 0.18788492
zee wye 8 0.59855401 0.97618139
hat wye 9 0.03144188 0.74955076
pan wye 10 0.50262601 0.95261836

View file

@ -0,0 +1,50 @@
- a: pan
b: pan
i: 1
x: 0.3467901443380824
"y": 0.7268028627434533
- a: eks
b: pan
i: 2
x: 0.7586799647899636
"y": 0.5221511083334797
- a: wye
b: wye
i: 3
x: 0.20460330576630303
"y": 0.33831852551664776
- a: eks
b: wye
i: 4
x: 0.38139939387114097
"y": 0.13418874328430463
- a: wye
b: pan
i: 5
x: 0.5732889198020006
"y": 0.8636244699032729
- a: zee
b: pan
i: 6
x: 0.5271261600918548
"y": 0.49322128674835697
- a: eks
b: zee
i: 7
x: 0.6117840605678454
"y": 0.1878849191181694
- a: zee
b: wye
i: 8
x: 0.5985540091064224
"y": 0.976181385699006
- a: hat
b: wye
i: 9
x: 0.03144187646093577
"y": 0.7495507603507059
- a: pan
b: wye
i: 10
x: 0.5026260055412137
"y": 0.9526183602969864

View file

@ -0,0 +1 @@
mlr --y2x cat ${CASEDIR}/input

View file

@ -0,0 +1,59 @@
a pan
b pan
i 1
x 0.34679014
y 0.72680286
a eks
b pan
i 2
x 0.75867996
y 0.52215111
a wye
b wye
i 3
x 0.20460331
y 0.33831853
a eks
b wye
i 4
x 0.38139939
y 0.13418874
a wye
b pan
i 5
x 0.57328892
y 0.86362447
a zee
b pan
i 6
x 0.52712616
y 0.49322129
a eks
b zee
i 7
x 0.61178406
y 0.18788492
a zee
b wye
i 8
x 0.59855401
y 0.97618139
a hat
b wye
i 9
x 0.03144188
y 0.74955076
a pan
b wye
i 10
x 0.50262601
y 0.95261836

View file

@ -0,0 +1,50 @@
- a: pan
b: pan
i: 1
x: 0.3467901443380824
"y": 0.7268028627434533
- a: eks
b: pan
i: 2
x: 0.7586799647899636
"y": 0.5221511083334797
- a: wye
b: wye
i: 3
x: 0.20460330576630303
"y": 0.33831852551664776
- a: eks
b: wye
i: 4
x: 0.38139939387114097
"y": 0.13418874328430463
- a: wye
b: pan
i: 5
x: 0.5732889198020006
"y": 0.8636244699032729
- a: zee
b: pan
i: 6
x: 0.5271261600918548
"y": 0.49322128674835697
- a: eks
b: zee
i: 7
x: 0.6117840605678454
"y": 0.1878849191181694
- a: zee
b: wye
i: 8
x: 0.5985540091064224
"y": 0.976181385699006
- a: hat
b: wye
i: 9
x: 0.03144187646093577
"y": 0.7495507603507059
- a: pan
b: wye
i: 10
x: 0.5026260055412137
"y": 0.9526183602969864

View file

@ -0,0 +1 @@
mlr --iyaml --ocsv cat ${CASEDIR}/input

View file

View file

@ -0,0 +1,3 @@
a,b,c
1,2,hello
10,20,world

View file

@ -0,0 +1,7 @@
a: 1
b: 2
c: hello
---
a: 10
b: 20
c: world

View file

@ -0,0 +1 @@
mlr --iyaml --oyaml --no-yarray cat ${CASEDIR}/input

View file

View file

@ -0,0 +1,5 @@
a: 1
b: 2
---
a: 3
b: 4

View file

@ -0,0 +1,5 @@
a: 1
b: 2
---
a: 3
b: 4