1
0
mirror of https://github.com/stedolan/jq.git synced 2024-05-11 05:55:39 +00:00

Documentation. Copious.

This commit is contained in:
Stephen Dolan
2012-09-18 17:51:53 +01:00
parent a4eea165bb
commit cf134909fd
25 changed files with 10269 additions and 0 deletions

6
docs/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
.DS_Store
.sass-cache
output/*
# Autogenerated from public/css/base.scss
public/css/base.css

54
docs/Rakefile Normal file
View File

@ -0,0 +1,54 @@
require 'bonsai'
require 'liquid'
require 'maruku'
require 'json'
module ExtraFilters
def markdownify(input)
Maruku.new(input).to_html
end
def sanitize(input)
input.gsub(/[^a-zA-Z0-9_]/,"")
end
def json(input)
input.to_json
end
def unique(input)
@n = (@n || 0) + 1
input + @n.to_s
end
end
Liquid::Template.register_filter(ExtraFilters)
task :serve do
begin
Bonsai.log "Press Control+C to quit"
require 'rack'
require 'sinatra'
require 'watch'
require 'launchy'
Bonsai.root_dir = Dir.pwd
server = fork {
app = Rack::Builder.app {
use Bonsai::StaticPassThrough, :root => Bonsai.root_dir + "/output", :urls => ["/"]
run Bonsai::DevelopmentServer
}
Rack::Handler.default.run(app, :Port => 5000) do
Launchy.open("http://localhost:5000/")
end
}
Watch.new("{content,templates,public}/**/*") { Bonsai::Exporter.process! }
rescue Interrupt
Process.kill("QUIT", server)
Process.wait(server)
exit
end
end

View File

@ -0,0 +1,239 @@
headline: Tutorial
body:
- text: |
Twitter have a JSON API, so let's play with that. This URL gets
us the last 5 tweets about JSON:
- command: "curl 'http://search.twitter.com/search.json?q=json&rpp=5&include_entities=true'"
result: |
{"completed_in":0.108,"max_id":247677287108067328,"max_id_str":"247677287108067328","next_page":"?page=2&max_id=247677287108067328&q=json&rpp=5&include_entities=1","page":1,"query":"json","refresh_url":"?since_id=247677287108067328&q=json&include_entities=1","results":[{"created_at":"Mon, 17 Sep 2012 12:44:01 +0000","entities":{"hashtags":[],"urls":[{"url":"http:\/\/t.co\/XRvh1ZVw","expanded_url":"http:\/\/jase.im\/Ri7I0M","display_url":"jase.im\/Ri7I0M","indices":[112,132]}],"user_mentions":[{"screen_name":"imagemechanics","name":"Jason Cotterell","id":57271393,"id_str":"57271393","indices":[3,18]}]},"from_user":"_AaronNg","from_user_id":79771704,"from_user_id_str":"79771704","from_user_name":"NgChenChong","geo":null,"id":247677287108067328,"id_str":"247677287108067328","iso_language_code":"en","metadata":{"result_type":"recent"},"profile_image_url":"http:\/\/a0.twimg.com\/profile_images\/2523558403\/ek8mo4j4beq84iw28gjl_normal.jpeg","profile_image_url_https":"https:\/\/si0.twimg.com\/profile_images\/2523558403\/ek8mo4j4beq84iw28gjl_normal.jpeg","source":"<a href="http:\/\/twitter.com\/">web<\/a>","text":"RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas>.\nhttp:\/\/t.co\/XRvh1ZVw","to_user":null,"to_user_id":0,"to_user_id_str":"0","to_user_name":null}, ...
- text: |
There's lots of info and no whitespace, so to make it a bit more
legible we pipe it through jq, telling jq to just spit the input
back at us using the expression `.`:
- command: "curl 'http://search.twitter.com/search.json?q=json&rpp=5&include_entities=true' | jq '.'"
result: |
{
"since_id_str": "0",
"since_id": 0,
"results_per_page": 5,
"completed_in": 0.108,
"max_id": 247677287108067330,
"max_id_str": "247677287108067328",
"next_page": "?page=2&max_id=247677287108067328&q=json&rpp=5&include_entities=1",
"page": 1,
"query": "json",
"refresh_url": "?since_id=247677287108067328&q=json&include_entities=1",
"results": [
{
"from_user_name": "NgChenChong",
"from_user_id_str": "79771704",
"from_user_id": 79771704,
"from_user": "_AaronNg",
"iso_language_code": "en",
"text": "RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas>.\nhttp://t.co/XRvh1ZVw",
"to_user": null
/* lots more fields... */
},
/* lots more results... */
]
}
- text: |
Let's pull out the first tweet:
- command: "curl 'http://search.twitter.com/search.json?q=json&rpp=5&include_entities=true' | jq '.results[0]'"
result: |
{
"from_user_name": "NgChenChong",
"from_user_id_str": "79771704",
"from_user_id": 79771704,
"from_user": "_AaronNg",
"iso_language_code": "en",
"text": "RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas>.\nhttp://t.co/XRvh1ZVw",
"to_user": null
/* lots more fields... */
},
- text: |
For the rest of the examples, I'll leave out the `curl` command - it's not going to change.
There's still a lot of info we don't care about there, so we'll
restrict it down to the most interesting fields.
- command: "jq '.results[0] | {from_user, text}'"
result: |
{
"text": "RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas>.\nhttp://t.co/XRvh1ZVw",
"from_user": "_AaronNg"
}
- text: |
The `|` operator in jq feeds the output of one filter
(`.results[0]` which gets the first element of the results
array) into the input of another (`{from_user, text}` which
builds an object of those two fields).
Now let's get the rest of the tweets:
- command: "jq '.results[] | {from_user, text}'"
result: |
{
"text": "RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas>.\nhttp://t.co/XRvh1ZVw",
"from_user": "_AaronNg"
}
{
"text": "RT @_kud: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas> -- http://t.co/Lhp92IqD",
"from_user": "blouerat"
}
{
"text": "Dynamic Forms Mobile App by pmadiset: Few Forms details are hosted on our server in the form of JSON. This JSON ... http://t.co/7KALdWaX",
"from_user": "cebu_iphone"
}
{
"text": "iPhone 5 website insanity - Video compressing using JPEG, JSON, and <canvas> http://t.co/28Jesbio (Oh #Apple, U So #Awesome...)",
"from_user": "dieswaytoofast"
}
{
"text": "RT @umutm: A very nice web-based JSON editor - http://t.co/M70snaIf",
"from_user": "Leolik"
}
- text: |
`.results[]` returns each element of the results array, one at a
time, which are all fed into `{from_user, text}`.
Data in jq is represented as streams of JSON values - every jq
expression runs for each value in its input stream, and can
produce any number of values to its output stream.
Streams are serialised by just separating JSON values with
whitespace. This is a `cat`-friendly format - you can just join
two JSON streams together and get a valid JSON stream.
If you want to get the output as a single array, you can tell jq to
"collect" all of the answers by wrapping the filter in square
brackets:
- command: "jq '[.results[] | {from_user, text}]'"
result: |
[
{
"text": "RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas>.\nhttp://t.co/XRvh1ZVw",
"from_user": "_AaronNg"
},
{
"text": "RT @_kud: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas> -- http://t.co/Lhp92IqD",
"from_user": "blouerat"
},
{
"text": "Dynamic Forms Mobile App by pmadiset: Few Forms details are hosted on our server in the form of JSON. This JSON ... http://t.co/7KALdWaX",
"from_user": "cebu_iphone"
},
{
"text": "iPhone 5 website insanity - Video compressing using JPEG, JSON, and <canvas> http://t.co/28Jesbio (Oh #Apple, U So #Awesome...)",
"from_user": "dieswaytoofast"
},
{
"text": "RT @umutm: A very nice web-based JSON editor - http://t.co/M70snaIf",
"from_user": "Leolik"
}
]
- text: |
- - -
Next, let's try getting the URLs out of those API results as
well. In each tweet, the Twitter API includes a field called
"entities" which looks like this:
{
"user_mentions": [],
"urls": [{
"indices": [83, 103],
"display_url": "bit.ly/StniqT",
"expanded_url": "http://bit.ly/StniqT",
"url": "http://t.co/28Jesbio"
}],
"hashtags": [
{"indices": [108, 114], "text": "Apple" },
{"indices": [121, 129], "text": "Awesome"}
]
}
We want to pull out all of the "url" fields inside that array of url
objects, and make a simple list of strings to go along with the
"from_user" and "text" fields we already have.
- command: "jq '.results[] | {from_user, text, urls: [.entities.urls[].url]}'"
result: |
{
"urls": [
"http://t.co/XRvh1ZVw"
],
"text": "RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas>.\nhttp://t.co/XRvh1ZVw",
"from_user": "_AaronNg"
}
{
"urls": [
"http://t.co/Lhp92IqD"
],
"text": "RT @_kud: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas> -- http://t.co/Lhp92IqD",
"from_user": "blouerat"
}
{
"urls": [
"http://t.co/7KALdWaX"
],
"text": "Dynamic Forms Mobile App by pmadiset: Few Forms details are hosted on our server in the form of JSON. This JSON ... http://t.co/7KALdWaX",
"from_user": "cebu_iphone"
}
{
"urls": [
"http://t.co/28Jesbio"
],
"text": "iPhone 5 website insanity - Video compressing using JPEG, JSON, and <canvas> http://t.co/28Jesbio (Oh #Apple, U So #Awesome...)",
"from_user": "dieswaytoofast"
}
{
"urls": [
"http://t.co/M70snaIf"
],
"text": "RT @umutm: A very nice web-based JSON editor - http://t.co/M70snaIf",
"from_user": "Leolik"
}
- text: |
Here we're making an object as before, but this time the urls
field is being set to `[.entities.urls[].url]`, which collects
all of the URLs defined in the entities object.
- text: |
- - -
asdf

View File

@ -0,0 +1,52 @@
headline: Download jq
body:
- text: |
jq is written in C and has no runtime dependencies, so it should be
possible to build it for nearly any platform. Prebuilt binaries are
available for Linux (64-bit x86) and OS X.
* [Download binary for 64-bit Linux](/download/linux/x68_64/jq)
* [Download binary for OS X](/download/osx/64/jq)
* [Download source](/download/source/jq.tgz)
jq is licensed under the MIT license. For all of the gory
details, read the file `COPYING` in the source distribution.
Hacking on jq
=============
If you want to work on jq, grab the source from
[https://github.com/stedolan/jq](https://github.com/stedolan/jq).
To build it from a git clone, you'll need to install a few
packages first:
* [Flex](http://www.gnu.org/software/flex/)
* [Bison](http://www.gnu.org/software/bison/)
* [Python](http://www.python.org)
* [GCC](http://gcc.gnu.org)
* [Make](http://www.gnu.org/software/make)
Most of these aren't necessary if you're just trying to compile
jq from the released tarball - that version has the
non-platform-specific build steps already done, so you'll only
need a C compiler and `make` to finish it off.
For Linux systems, these will all be in your system's package
manager, and if you do development on the machine they're most
likely already installed. I have no idea how to get these
installed on OS X, you're on your own there.
`flex` and `bison` are used to generate the lexer and parser for
jq, and some python scripts generate the UTF8 encoding tables
needed for JSON parsing.
Building the documentation
--
jq's documentation is compiled into static HTML using
[Bonsai](http://www.tinytree.info). To view the documentation
locally, run `rake serve` from the docs/ subdirectory.

View File

@ -0,0 +1,688 @@
headline: jq Manual
sections:
- title: Basics
body: "{ some *intro* text \n\n\n}\n"
entries:
- title: "`.`"
body: |
The absolute simplest (and least interesting) jq expression
is `.`. This is a jq expression that takes its input and
produces it unchanged as output.
Since jq by default pretty-prints all output, this trivial
program can be a useful way of formatting JSON output from,
say, `curl`.
examples:
- program: '.'
input: '"Hello, world!"'
output: ['"Hello, world!"']
- title: "`.foo`"
body: |
The simplest *useful* jq expression is .foo. When given a
JSON object (aka dictionary or hash) as input, it produces
the value at the key "foo", or null if there\'s none present.
examples:
- program: '.foo'
input: '{"foo": 42, "bar": "less interesting data"}'
output: [42]
- program: '.foo'
input: '{"notfoo": true, "alsonotfoo": false}'
output: ['null']
- title: "`.[foo]`"
body: |
You can also look up fields of an object using syntax like
`.["foo"]` (.foo above is a shorthand version of this). This
one works for arrays as well, if the key is an
integer. Arrays are zero-based (like javascript), so .[2]
returns the third element of the array.
examples:
- program: '.[0]'
input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]'
output: ['{"name":"JSON", "good":true}']
- program: '.[2]'
input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]'
output: ['null']
- title: "`.[]`"
body: |
If you use the `.[foo]` syntax, but omit the index
entirely, it will return *all* of the elements of an
array. Running `.[]` with the input `[1,2,3]` will produce the
numbers as three seperate results, rather than as a single
array.
examples:
- program: '.[]'
input: '[{name":"JSON", "good":true}, {"name":"XML", "good":false}]'
output:
- '{"name":"JSON", "good":true}'
- '{"name":"XML", "good":false}'
- program: '.[]'
input: '[]'
output: []
- title: "`,`"
body: |
If two jq expressions are separated by a comma, then the
input will be fed into both and there will be multiple
outputs: first, all of the outputs produced by the left
expression, and then all of the outputs produced by the
right. For instance, jq expression `.foo, .bar`, produces
both the "foo" fields and "bar" fields as separate outputs.
examples:
- program: '.foo, .bar'
input: '{"foo": 42, "bar": "something else", "baz": true}'
output: ['42', '"something else"']
- program: "[.user, .projects[]]"
input: '{"user":"stedolan", "projects": ["jq", "wikiflow"]}'
output: ['"stedolan"', '"jq"', '"wikiflow"']
- program: '.[4,2]'
input: '["a","b","c","d","e"]'
output: ['"d"', '"c"']
- title: "`|`"
body: |
The | operator combines two jq expressions by feeding the output(s) of
the one on the left into the input of the one on the right. It\'s
pretty much the same as the Unix shell\'s pipe, if you\'re used to
that.
If the one on the left produces multiple results, the one on
the right will be run for each of those results. So, the
expression `.[] | .foo` retrieves the "foo" field of each
element of the input array.
examples:
- program: '.[] | .name'
input: '[{name":"JSON", "good":true}, {"name":"XML", "good":false}]'
output: ['"JSON"', '"XML"']
- title: Types and Values
body: |
jq supports the same set of datatypes as JSON - numbers,
strings, booleans, arrays, objects (which in JSON-speak are
hashes with only string keys), and "null".
Booleans, null, strings and numbers are written the same way as
in javascript. Just like everything else in jq, these simple
values take an input and produce an output - `42` is a valid jq
expression that takes an input, ignores it, and returns 42
instead.
entries:
- title: Array construction - `[]`
body: |
As in JSON, `[]` is used to construct arrays, as in
`[1,2,3]`. The elements of the arrays can be any jq
expression. All of the results produced by all of the
expressions are collected into one big array. You can use it
to construct an array out of a known quantity of values (as
in `[.foo, .bar, .baz]`) or to "collect" all the results of a
jq expression into an array (as in `[.items[].name]`)
Once you understand the "," operator, you can look at jq\'s array
syntax in a different light: the expression [1,2,3] is not using a
built-in syntax for comma-separated arrays, but is instead applying
the `[]` operator (collect results) to the expression 1,2,3 (which
produces three different results).
If you have a jq expression `X` that produces four results,
then the expression `[X]` will produce a single result, an
array of four elements.
examples:
- program: "[.user, .projects[]]"
input: '{"user":"stedolan", "projects": ["jq", "wikiflow"]}'
output: ['["stedolan", "jq", "wikiflow"]']
- title: Objects - `{}`
body: |
Like JSON, `{}` is for constructing objects (aka
dictionaries or hashes), as in: `{"a": 42, "b": 17}`.
If the keys are "sensible" (all alphabetic characters), then
the quotes can be left off. The value can be any expression
(although you may need to wrap it in parentheses if it\'s a
complicated one), which gets applied to the {} expression\'s
input (remember, all jq expressions have an input and an
output).
{foo: .bar}
will produce the JSON object `{"foo": 42}` if given the JSON
object `{"bar":42, "baz":43}`. You can use this to select
particular fields of an object: if the input is an object
with "user", "title", "id", and "content" fields and you
just want "user" and "title", you can write
{user: .user, title: .title}
Because that\'s so common, there\'s a shortcut syntax: `{user, title}`.
If one of the expressions produces multiple results,
multiple dictionaries will be produced. If the input\'s
{"user":"stedolan","titles":["JQ Primer", "More JQ"]}
then the expression
{user, title: .titles[]}
will produce two outputs:
{"user":"stedolan", "title": "JQ Primer"}
{"user":"stedolan", "title": "More JQ"}
Putting parentheses around the key means it will be evaluated as an
expression. With the same input as above,
{(.user): .titles}
produces
{"stedolan": ["JQ Primer", "More JQ"]}
examples:
- program: '{user, title: .titles[]}'
input: '{"user":"stedolan","titles":["JQ Primer", "More JQ"]}'
output:
- '{"user":"stedolan", "title": "JQ Primer"}'
- '{"user":"stedolan", "title": "More JQ"}'
- program: '{(.user): .titles}'
input: '{"user":"stedolan","titles":["JQ Primer", "More JQ"]}'
output: ['{"stedolan": ["JQ Primer", "More JQ"]}']
- title: Builtin operators and functions
body: |
Some jq operator (for instance, `+`) do different things
depending on the type of their arguments (arrays, numbers,
etc.). However, jq never does implicit type conversions. If you
try to add a string to an object you'll get an error message and
no result.
entries:
- title: Addition - `+`
body: |
The operator `+` takes two jq expressions, applies them both
to the same input, and adds the results together. What
"adding" means depends on the types involved:
- **Numbers** are added by normal arithmetic.
- **Arrays** are added by being concatenated into a larger array.
- **Strings** are added by being joined into a larger string.
- **Objects** are added by merging, that is, inserting all
the key-value pairs from both objects into a single
combined object. If both objects contain a value for the
same key, the object on the right of the `+` wins.
examples:
- program: '.a + 1'
input: '{"a": 7}'
output: '{"a": 8}'
- program: '.a + .b'
input: '{"a": [1,2], "b": [3,4]}'
output: ['[1,2,3,4]']
- program: '{a: 1} + {b: 2} + {c: 3} + {a: 42}'
input: 'null'
output: ['{"a": 42, "b": 2, "c": 3}']
- title: Subtraction - `-`
body: |
As well as normal arithmetic subtraction on numbers, the `-`
operator can be used on arrays to remove all occurences of
the second array's elements from the first array.
examples:
- program: '4 - .a'
input: '{"a":3}'
output: ['1']
- program: . - ["xml", "yaml"]
input: '["xml", "yaml", "json"]'
output: ['["json"]']
- title: Multiplication, division - `*` and `/`
body: |
These operators only work on numbers, and do the expected.
examples:
- program: '10 / . * 3'
input: 5
output: [6]
- title: `length`
body: |
The builtin function `length` gets the length of various
different types of value:
- The length of a **string** is the number of Unicode
codepoints it contains (which will be the same as its
JSON-encoded length in bytes if it's pure ASCII).
- The length of an **array** is the number of elements.
- The length of an **object** is the number of key-value pairs.
- The length of **null** is zero.
examples:
- program: '.[] | length'
input: '[[1,2], "string", {"a":2}, null]'
output: [2, 6, 1, 0]
- title: `tonumber`
body: |
The `tonumber` function parses its input as a number. It
will convert correctly-formatted strings to their numeric
equivalent, leave numbers alone, and give an error on all other input.
examples:
- program: '.[] | tonumber'
input: '[1, "1"]'
output: [1,1]
- title: `tostring`
body: |
The `tostring` function prints its input as a
string. Strings are left unchanged, and all other values are
JSON-encoded.
examples:
- program: '.[] | tostring'
input: '[1, "1", [1]]'
output: ['"1"', '"1"', '"[1]"']
- title: "String interpolation - `@(text)`"
body: |
jq supports an alternative syntax for strings. Instead of
"foo", you can write `@(foo)`. When using this syntax,
`%(expression)` may be used to insert the value of
`expression` into the string (converted with `tostring`).
String interpolation does not occur for normal double-quoted
strings (like `"foo"`) in order to be fully compatible with
JSON.
All of the usual JSON escapes (`\n`, `\r` and the like) work
inside `@()`-quoted strings, as well as `\%` and `\)` if
those characters are needed literally.
examples:
- program: '@(The input was %(.), which is one less than %(.+1))'
input: '42'
output: ['"The input was 42, which is one less than 43"']
- title: Conditionals and Comparisons
entries:
- title: `==`, `!=`
body: |
The expression 'a == b' will produce 'true' if the result of a and b
are equal (that is, if they represent equivalent JSON documents) and
'false' otherwise. In particular, strings are never considered equal
to numbers. If you're coming from Javascript, jq's == is like
Javascript's === - considering values equal only when they have the
same type as well as the same value.
!= is "not equal", and 'a != b' returns the opposite value of 'a == b'
examples:
- program: '.[] == 1'
input: '[1, 1.0, "1", "banana"]'
output: ['[true, true, false, false]']
- title: if-then-else
body: |
`if A then B else C end` will act the same as `B` if `A`
produces a value other than false or null, but act the same
as `C` otherwise.
Checking for false or null is a simpler notion of
"truthiness" than is found in Javascript or Python, but it
means that you'll sometimes have to be more explicit about
the condition you want: you can't test whether, e.g. a
string is empty using `if .name then A else B end`, you'll
need something more like 'if (.name | count) > 0 then A else
B end' instead.
If the condition A produces multiple results, it is
considered "true" if any of those results is not false or
null. If it produces zero results, it's considered false.
More cases can be added to an if using `elif A then B` syntax.
examples:
- program: |-
if . == 0 then
"zero"
elif . == 1 then
"one"
else
"many"
end
input: 2
output: ['"many"']
- title: and/or/not
body: |
jq supports the normal Boolean operators and/or/not. They have the
same standard of truth as if expressions - false and null are
considered "false values", and anything else is a "true value".
If an operand of one of these operators produces multiple
results, the operator itself will produce a result for each input.
`not` is in fact a builtin function rather than an operator,
so it is called as a filter to which things can be piped
rather than with special syntax, as in `.foo and .bar |
not`.
These three only produce the values "true" and "false", and
so are only useful for genuine Boolean operations, rather
than the common Perl/Python/Ruby idiom of
"value_that_may_be_null or default". If you want to use this
form of "or", picking between two values rather than
evaluating a condition, see the "//" operator below.
examples:
- program: '42 and "a string"'
input: 'null'
output: ['true']
- program: '(true, false) or false'
input: 'null'
output: ['true', 'false']
- program: '(true, false) and (true, false)'
input: 'null'
output: ['true', 'false', 'false', 'false']
- program: '[true, false | not]'
input: 'null'
output: ['[false, true]']
- title: Alternative operator - `//`
body: |
A jq expression of the form `a // b` produces the same
results as `a`, if `a` produces results other than `false`
and `null`. Otherwise, `a // b` produces the same results as `b`.
This is useful for providing defaults: `.foo or 1` will
evaluate to `1` if there's no `.foo` element in the
input. It's similar to how `or` is sometimes used in Python
(jq's `or` operator is reserved for strictly Boolean
operations).
examples:
- program: '.foo // 42'
input: '{"foo": 19}'
output: [19]
- program: '.foo // 42'
input: '{}'
output: [42]
- title: Variables and Functions
body: |
Variables are an absolute necessity in most programming languages, but
they're relegated to an "advanced feature" in jq.
In most languages, variables are the only means of passing around
data. If you calculate a value, and you want to use it more than once,
you'll need to store it in a variable. To pass a value to another part
of the program, you'll need that part of the program to define a
variable (as a function parameter, object member, or whatever) in
which to place the data.
It is also possible to define functions in jq, although this is
is a feature whose biggest use is defining jq's standard library
(many jq functions such as `map` and `find` are in fact written
in jq).
entries:
- title: Variables
body: |
In jq, all jq expressions have an input and an output, so manual
plumbing is not necessary to pass a value from one part of a program
to the next. Many expressions, for instance `a + b`, pass their input
to two distinct subexpressions (here `a` and `b` are both passed the
same input), so variables aren't usually necessary in order to use a
value twice.
For instance, calculating the average value of an array of numbers
requires a few variables in most languages - at least one to hold the
array, perhaps one for each element or for a loop counter. In jq, it's
simply `add / length` - the `sum` expression is given the array and
produces its sum, and the `count` expression is given the array and
produces its length.
So, there's generally a cleaner way to solve most problems in jq that
defining variables. Still, sometimes they do make things easier, so jq
lets you define variables using `expression as $variable`. All
variable names start with `$`. Here's a slightly uglier version of the
array-averaging example:
length as $array_length | add / $array_length
We'll need a more complicated problem to find a situation where using
variables actually makes our lives easier.
Suppose we have an array of blog posts, with "author" and "title"
fields, and another object which is used to map author usernames to
real names. Our input looks like:
{"posts": [{"title": "Frist psot", "author": "anon"},
{"title": "A well-written article", "author": "person1"}],
"realnames": {"anon": "Anonymous Coward",
"person1": "Person McPherson"}}
We want to produce the posts with the author field containing a real
name, as in:
{"title": "Frist psot", "author": "Anonymous Coward"}
{"title": "A well-written article", "author": "Person McPherson"}
We use a variable, $names, to store the realnames object, so that we
can refer to it later when looking up author usernames:
.realnames as $names | .posts[] | {title, author: $names[.author]}
The expression "asdf as $x" runs asdf, puts the result in $x, and
returns the original input. Apart from the side-effect of binding the
variable, it has the same effect as ".".
Variables are scoped over the rest of the expression that defines
them, so
.realnames as $names | (.posts[] | {title, author: $names[.author]})
will work, but
(.realnames as $names | .posts[]) | {title, author: $names[.author]}
won't.
examples:
- program: '.bar as $x | .foo | . + $x'
input: '{"foo":10, "bar":200}'
output: ['210']
- title: 'Defining Functions'
body: |
You can give a jq expression a name using "def" syntax:
def increment: . + 1;
From then on, `increment` is usable as a filter just like a
builtin function (in fact, this is how some of the builtins
are defined). A function may take arguments:
def map(f): [.[] | f];
Arguments are passed as jq expressions, not as values. The
same argument may be referenced multiple times with
different inputs (here `f` is run for each element of the
input array). Arguments to a function work more like
callbacks than like value arguments.
If you want the value-argument behaviour for defining simple
functions, you can just use a variable:
def addvalue(f): f as $value | map(, + $value);
With that definition, `addvalue(.foo)` will add the current
input's `.foo` field to each element of the array.
examples:
- program: 'def addvalue(f): map(. + [$value]); addvalue(.[0])'
input: '[[1,2],[10,20]]'
output: ['[[1,2,1], [10,20,10]]']
- program: 'def addvalue(f): f as $x | map (. + $x); addvalue(.[0])'
input: '[[1,2],[10,20]]'
output: ['[[1,2,[1,2]], [10,20,[1,2]]]']
- title: Assignment
body: |
Assignment works a little differently in jq than in most
programming languages. jq doesn't distinguish between references
to and copies of something - two objects or arrays are either
equal or not equal, without any further notion of being "the
same object" or "not the same object".
If an object has two fields which are arrays, `.foo` and `.bar`,
and you append something to `.foo`, then `.bar` will not get
bigger. Even if you've just set `.bar = .foo`. If you're used to
programming in languages like Python, Java, Ruby, Javascript,
etc. then you can think of it as though jq does a full deep copy
of every object before it does the assignment (for performance,
it doesn't actually do that, but that's the general idea).
entries:
- title: "`=`"
body: |
The jq expression `.foo = 1` will take as input an object
and produce as output an object with the "foo" field set to
1. There is no notion of "modifying" or "changing" something
in jq - all jq values are immutable. For instance,
.foo = .bar | .foo.baz = 1
will not have the side-effect of setting .bar.baz to be set
to 1, as the similar-looking program in Javascript, Python,
Ruby or other languages would. Unlike these languages (but
like Haskell and some other functional languages), there is
no notion of two arrays or objects being "the same array" or
"the same object". They can be equal, or not equal, but if
we change one of them in no circumstances will the other
change behind our backs.
This means that it's impossible to build circular values in
jq (such as an array whose first element is itself). This is
quite intentional, and ensures that anything a jq program
can produce can be represented in JSON.
- title: "`|=`"
body: |
As well as the assignment operator '=', jq provides the "update"
operator '|=', which takes a jq expression on the right-hand side and
works out the new value for the property being assigned to by running
the old value through this expression. For instance, .foo |= .+1 will
build an object with the "foo" field set to the input's "foo" plus 1.
This example should show the difference between '=' and '|=':
Provide input '{"a": {"b": 10}, "b": 20}' to the programs:
.a = .b
.a |= .b
The former will set the "a" field of the input to the "b" field of the
input, and produce the output {"a": 20}. The latter will set the "a"
field of the input to the "a" field's "b" field, producing {"a": 10}.
- title: "`+=`, `-=`, `*=`, `/=`, `//=`"
body: |
jq has a few operators of the form `a op= b`, which are all
equivalent to `a |= . op b`. So, `+= 1` can be used to increment values.
examples:
- program: .foo += 1
input: '{"foo": 42}'
output: ['{"foo": 43}']
- title: Complex assignments
body: |
Lots more things are allowed on the left-hand side of a jq assignment
than in most langauges. We've already seen simple field accesses on
the left hand side, and it's no surprise that array accesses work just
as well:
.posts[0].title = "JQ Manual"
What may come as a surprise is that the expression on the left may
produce multiple results, referring to different points in the input
document:
.posts[].comments |= . + ["this is great"]
That example appends the string "this is great" to the "comments"
array of each post in the input (where the input is an object with a
field "posts" which is an array of posts).
When jq encounters an assignment like 'a = b', it records the "path"
taken to select a part of the input document while executing a. This
path is then used to find which part of the input to change while
executing the assignment. Any jq expression may be used on the
left-hand side of an equals - whichever paths it selects from the
input will be where the assignment is performed.
This is a very powerful operation. Suppose we wanted to add a comment
to blog posts, using the same "blog" input above. This time, we only
want to comment on the posts written by "stedolan". We can find those
posts using the "select" function described earlier:
.posts[] | select(.author == "stedolan")
The paths provided by this operation point to each of the posts that
"stedolan" wrote, and we can comment on each of them in the same way
that we did before:
(.posts[] | select(.author == "stedolan") | .comments) |= . + ["terrible."]

View File

@ -0,0 +1,12 @@
headline: jq
blurb: |
jq is a command-line JSON processor.
body: |
Go read the [tutorial](/tutorial) for more, or the [manual](/manual)
for *way* more.

28
docs/public/.htaccess Normal file
View File

@ -0,0 +1,28 @@
DirectoryIndex index.html
FileETag All
# Compress all static assets
<IfModule mod_deflate.c>
# compress content with type html, text, and css
AddOutputFilterByType DEFLATE text/css text/html text/javascript application/javascript application/x-javascript text/js text/plain text/xml
<IfModule mod_headers.c>
# properly handle requests coming from behind proxies
Header append Vary User-Agent
</IfModule>
</IfModule>
# Cache, aggressively
<IfModule mod_expires.c>
ExpiresActive On
ExpiresDefault "access plus 10 days"
<FilesMatch "\.(eot|ttf|otf)$">
ExpiresDefault "access plus 10 years"
</filesMatch>
</IfModule>
# Mime-types
AddType application/vnd.ms-fontobject .eot
AddType font/ttf .ttf
AddType font/otf .otf

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

5774
docs/public/bootstrap/css/bootstrap.css vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

2027
docs/public/bootstrap/js/bootstrap.js vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

72
docs/public/css/base.scss Normal file
View File

@ -0,0 +1,72 @@
@charset "utf-8";
body {
padding-top: 60px;
}
footer {
background-color: #F5F5F5;
padding: 40px 0;
height: 100px;
margin-top: 40px;
color: #999999;
}
section {
padding-top: 30px;
}
.manual-example {
border-top: 1px solid #E5E5E5;
}
.manual-example td {
white-space: pre-wrap;
font-family: Monaco, Menlo, Consolas, "Courier New", monospace;
}
.manual-example td.jqprogram {
font-weight: bold;
}
.manual-example th {
text-align: right;
padding-right: 10px;
}
.tutorial-example {
position: relative;
margin-bottom: 10px;
}
.tutorial-example pre {
margin-bottom: 0px;
}
.tutorial-example a {
position: absolute;
top: 0px;
right: 0px;
padding: 15px 8px;
color: #777777;
font-weight: bold;
line-height: 10px;
font-size: 12px;
border-left: 1px solid #DDDDDD;
bottom: 0;
display: block;
}
#blurb {
padding-top: 20px;
}
#blurb p {
font-size: 20pt;
}
h3 code {
border: 0;
font-size: 20px;
}

BIN
docs/public/jq.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

2
docs/public/robots.txt Normal file
View File

@ -0,0 +1,2 @@
User-agent: *
Allow: /

11
docs/site.yml Normal file
View File

@ -0,0 +1,11 @@
# The key value pairs found below are available within the templates.
jq_version: 1.0
footer: |
This website is made with [Bonsai](http://www.tinytree.info) and
[Twitter Boostrap](http://twitter.github.com/bootstrap/). jq is
licensed under the MIT license (code) and the
[CC-BY-3.0](http://creativecommons.org/licenses/by/3.0/) license
(docs).

34
docs/templates/default.liquid vendored Normal file
View File

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
{% include "shared/head" %}
<body id="{{slug}}">
{% include "shared/header" %}
<div class="container">
<div class="row">
<h1>{{headline}}</h1>
{% for item in body %}
{% if item.text %}
{{ item.text | markdownify }}
{% endif %}
{% if item.command %}
{% capture resultID %}{{ "result" | unique}}{% endcapture %}
<div class="tutorial-example">
<div class="accordion-heading">
<pre>{{item.command}}</pre>
<a data-toggle="collapse" href="#{{resultID}}">Show result</a>
</div>
<div id="{{resultID}}" class="accordion-body collapse"><pre>{{item.result}}</pre></div>
</div>
{% endif %}
{% endfor %}
</div>
</div>
{% include "shared/footer" %}
</body>
</html>

38
docs/templates/index.liquid vendored Normal file
View File

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="en">
{% include "shared/head" %}
<body id="{{slug}}">
{% include "shared/header" %}
<div class="container">
<div class="row">
<div class="hero-unit">
<img src="/jq.png" style="width: 400px; height: 220px; float: left; margin-right: 60px">
<div id="blurb">
{{blurb | markdownify}}
<div class="btn-group" style="float:right">
<a class="btn btn-primary dropdown-toggle" data-toggle="dropdown" href="#">
Download jq-{{jq_version}}
<span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li><a href="/download/linux/x68_64/jq">Linux (x86_64)</a></li>
<li><a href="/download/osx/64/jq">OS X (64-bit)</a></li>
<li><a href="/download">Other platforms and source</a></li>
</ul>
</div>
</div>
<div style="clear:both;"></div>
</div>
</div>
<div class="row">
{{body | markdownify}}
</div>
</div>
{% include "shared/footer" %}
</body>
</html>

109
docs/templates/manual.liquid vendored Normal file
View File

@ -0,0 +1,109 @@
<!DOCTYPE html>
<html lang="en">
{% include "shared/head" %}
<body id="{{slug}}" data-spy="scroll" data-target="#navcolumn" data-offset="100">
{% include "shared/header" %}
<div class="container">
<div class="row">
<div class="span3" id="navcolumn">
<div class="affix">
<h4>Contents</h4>
<ul class="nav nav-pills nav-stacked">
{% for section in sections %}
<li {% if forloop.first %} class="active" {% endif %}>
<a href="#{{section.title | sanitize}}">{{section.title}}</a>
</li>
{% endfor %}
</ul>
<form class="form-search">
<script type="text/javascript">
var section_map = {
{% for section in sections %}
{% for entry in section.entries %}
{{entry.title | json}} : {{entry.title | sanitize | json}},
{% endfor %}
{{section.title | json}} : {{section.title | sanitize | json}}
{% unless forloop.last %},{% endunless %}
{% endfor %}
};
var section_names = $.map(section_map, function(v,k){return k});
$(function(){
$('#searchbox').typeahead({source: section_names})
$('#searchbox').change(function() {
if ($(this).val() in section_map) {
location.hash = '#' + section_map[$(this).val()];
}
});
});
</script>
<input type="text"
class="input-medium search-query"
placeholder="Search"
autocomplete="off"
id="searchbox">
</form>
</div>
</div>
<div class="span9">
<h1>{{headline}}</h1>
{% for section in sections %}
<section id="{{section.title | sanitize}}">
<h2>{{section.title}}</h2>
{{section.body | markdownify}}
{% for entry in section.entries %}
<section id="{{entry.title | sanitize}}">
<h3>
{{entry.title | markdownify}}
{% if entry.subtitle %}<small>{{entry.subtitle}}</small>{% endif %}
</h3>
{{entry.body | markdownify}}
{% if entry.examples %}
<div>
{% capture exampleID %}{{ "" | unique }}{% endcapture %}
<a data-toggle="collapse" href="#example{{exampleID}}">
<i class="icon-chevron-right"></i>
{% if entry.examples[1] %}Examples{%else%}Example{%endif%}
</a>
<div id="example{{exampleID}}" class="collapse">
{% for example in entry.examples %}
<table class="manual-example">
<tr><th></th><td class="jqprogram">jq '{{example.program}}'</td></tr>
<tr><th>Input</th><td>{{example.input}}</td></tr>
{% unless example.output[0] %}
<tr>
<th>Output</th>
<td><i>none</i></td>
</tr>
{% endunless %}
{% for output in example.output %}
<tr>
{% if forloop.index == 1 %}
<th>Output</th>
{% else %}
<th></th>
{% endif %}
<td>{{output}}</td>
</tr>
{% endfor %}
</table>
{% endfor %}
</div>
</div>
{% endif %}
</section>
{% endfor %}
</section>
{% endfor %}
</div>
</div>
</div>
{% include "shared/footer" %}
</body>
</html>

5
docs/templates/shared/_footer.liquid vendored Normal file
View File

@ -0,0 +1,5 @@
<footer>
<div class="container">
{{ footer | markdownify }}
</div>
</footer>

12
docs/templates/shared/_head.liquid vendored Normal file
View File

@ -0,0 +1,12 @@
<head>
<meta charset=UTF-8>
<title>{{headline}} | jq</title>
<link rel="stylesheet" href="/bootstrap/css/bootstrap.css" type="text/css">
<link rel="stylesheet" href="/css/base.css" type="text/css">
<!--[if IE]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
<script src="/bootstrap/js/bootstrap.js"></script>
</head>

24
docs/templates/shared/_header.liquid vendored Normal file
View File

@ -0,0 +1,24 @@
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="brand" href="/">jq</a>
<div class="nav-collapse collapse">
<ul class="nav">
{% for item in navigation %}
<li {% if item.permalink == permalink %} class="active" {% endif %}>
<a href="{{item.permalink}}">{{item.name}}</a>
</li>
{% endfor %}
<li><a href="https://github.com/stedolan/jq/issues">Issues</a></li>
<li><a href="https://github.com/stedolan/jq">Source</a></li>
</ul>
</div>
</div>
</div>
</div>