The “xo” Utility

The xo utility allows command line access to the functionality of the libxo library. Using xo, shell scripts can emit XML, JSON, and HTML using the same commands that emit text output.

The style of output can be selected using a specific option: “-X” for XML, “-J” for JSON, “-H” for HTML, or “-T” for TEXT, which is the default. The “–style <style>” option can also be used. The standard set of “–libxo” options are available (see Command-line Arguments), as well as the LIBXO_OPTIONS environment variable.

The xo utility accepts a format string suitable for xo_emit and a set of zero or more arguments used to supply data for that string:

  xo "The {k:name} weighs {:weight/%d} pounds.\n" fish 6

TEXT:
  The fish weighs 6 pounds.

XML:
  <name>fish</name>
  <weight>6</weight>

JSON:
  "name": "fish",
  "weight": 6

HTML:
  <div class="line">
    <div class="text">The </div>
    <div class="data" data-tag="name">fish</div>
    <div class="text"> weighs </div>
    <div class="data" data-tag="weight">6</div>
    <div class="text"> pounds.</div>
  </div>

The --wrap $path option can be used to wrap emitted content in a specific hierarchy. The path is a set of hierarchical names separated by the ‘/’ character:

  xo --wrap top/a/b/c '{:tag}' value

XML:
  <top>
    <a>
      <b>
        <c>
          <tag>value</tag>
        </c>
      </b>
    </a>
  </top>

JSON:
  "top": {
    "a": {
      "b": {
        "c": {
          "tag": "value"
        }
      }
    }
  }

The --open $path and --close $path can be used to emit hierarchical information without the matching close and open tag. This allows a shell script to emit open tags, data, and then close tags. The --depth option may be used to set the depth for indentation. The --leading-xpath may be used to prepend data to the XPath values used for HTML output style:

EXAMPLE:
  #!/bin/sh
  xo --open top/data
  xo --depth 2 '{:tag}' value
  xo --close top/data

XML:
  <top>
    <data>
      <tag>value</tag>
    </data>
  </top>

JSON:
  "top": {
    "data": {
      "tag": "value"
    }
  }

When making partial lines of output (where the format string does not include a newline), use the --continuation option to let secondary invocations know they are adding data to an existing line.

When emitting a series of objects, use the --not-first option to ensure that any details from the previous object (e.g. commas in JSON) are handled correctly.

Use the --top-wrap option to ensure any top-level object details are handled correctly, e.g. wrap the entire output in a top-level set of braces for JSON output.

EXAMPLE:
  #!/bin/sh
  xo --top-wrap --open top/data
  xo --depth 2 'First {:tag} ' value1
  xo --depth 2 --continuation 'and then {:tag}\n' value2
  xo --top-wrap --close top/data

TEXT:
  First value1 and then value2

HTML:
  <div class="line">
    <div class="text">First </div>
    <div class="data" data-tag="tag">value1</div>
    <div class="text"> </div>
    <div class="text">and then </div>
    <div class="data" data-tag="tag">value2</div>
  </div>

XML:
  <top>
    <data>
      <tag>value1</tag>
      <tag>value2</tag>
    </data>
  </top>

JSON:
  {
    "top": {
      "data": {
      "tag": "value1",
      "tag": "value2"
      }
    }
  }

Lists and Instances

A “list” is set of one or more instances that appear under the same parent. The instances contain details about a specific object. One can think of instances as objects or records. A call is needed to open and close the list, while a distinct call is needed to open and close each instance of the list.

Use the --open-list and --open-instances to open lists and instances. Use the --close-list and --close-instances to close them. Each of these options take a name parameter, providing the name of the list and instance.

In the following example, a list named “machine” is created with three instances:

opts="--json"
xo $opts --open-list machine
NF=
for name in red green blue; do
    xo $opts --depth 1 $NF --open-instance machine
    xo $opts --depth 2 "Machine {k:name} has {:memory}\n" $name 55
    xo $opts --depth 1 --close-instance machine
    NF=--not-first
done
xo $opts $NF --close-list machine

The normal libxo functions use a state machine to help these transitions, but since each xo command is invoked independent of the previous calls, the state must be passed in explicitly via these command line options.

The --instance option can be used to treat a single xo invocation as an instance with the given set of fields:

% xo --libxo:XP --instance foo 'The {:product} is {:status}\n' stereo "in route"
<foo>
  <product>stereo</product>
  <status>in route</status>
</foo>

Command Line Options

Usage: xo [options] format [fields]
  --close <path>        Close tags for the given path
  --close-instance <name> Close an open instance name
  --close-list <name>   Close an open list name
  --continuation OR -C  Output belongs on same line as previous output
  --depth <num>         Set the depth for pretty printing
  --help                Display this help text
  --html OR -H          Generate HTML output
  --instance OR -I <name> Wrap in an instance of the given name
  --json OR -J          Generate JSON output
  --leading-xpath <path> Add a prefix to generated XPaths (HTML)
  --not-first           Indicate this object is not the first (JSON)
  --open <path>         Open tags for the given path
  --open-instance <name> Open an instance given by name
  --open-list <name>   Open a list given by name
  --option <opts> -or -O <opts>  Give formatting options
  --pretty OR -p        Make 'pretty' output (add indent, newlines)
  --style <style>       Generate given style (xml, json, text, html)
  --text OR -T          Generate text output (the default style)
  --top-wrap            Generate a top-level object wrapper (JSON)
  --version             Display version information
  --warn OR -W          Display warnings in text on stderr
  --warn-xml            Display warnings in xml on stdout
  --wrap <path>         Wrap output in a set of containers
  --xml OR -X           Generate XML output
  --xpath               Add XPath data to HTML output)

Example

% xo 'The {:product} is {:status}\n' stereo "in route"
The stereo is in route
% xo -p -X 'The {:product} is {:status}\n' stereo "in route"
<product>stereo</product>
<status>in route</status>
% xo --libxo xml,pretty 'The {:product} is {:status}\n' stereo "in route"
<product>stereo</product>
<status>in route</status>