mirror of
https://github.com/mikefarah/yq.git
synced 2026-03-10 15:54:26 +00:00
Compare commits
2 Commits
eaf26894c1
...
2f56a8df95
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f56a8df95 | ||
|
|
d38fd1f256 |
@ -37,6 +37,7 @@
|
||||
* [Eval](operators/eval.md)
|
||||
* [File Operators](operators/file-operators.md)
|
||||
* [Filter Operator](operators/filter.md)
|
||||
* [First Operator](operators/first.md)
|
||||
* [Flatten](operators/flatten.md)
|
||||
* [Group By](operators/group-by.md)
|
||||
* [Has](operators/has.md)
|
||||
|
||||
@ -1,8 +1,63 @@
|
||||
# How it works
|
||||
# Expression Syntax: A Visual Guide
|
||||
In `yq`, expressions are made up of operators and pipes. A context of nodes is passed through the expression, and each operation takes the context as input and returns a new context as output. That output is piped in as input for the next operation in the expression.
|
||||
|
||||
In `yq` expressions are made up of operators and pipes. A context of nodes is passed through the expression and each operation takes the context as input and returns a new context as output. That output is piped in as input for the next operation in the expression. To begin with, the context is set to the first yaml document of the first yaml file (if processing in sequence using eval).
|
||||
Let's break down the process step by step using a diagram. We'll start with a single YAML document, apply an expression, and observe how the context changes at each step.
|
||||
|
||||
Lets look at a couple of examples.
|
||||
Given a document like:
|
||||
|
||||
```yaml
|
||||
root:
|
||||
items:
|
||||
- name: apple
|
||||
type: fruit
|
||||
- name: carrot
|
||||
type: vegetable
|
||||
- name: banana
|
||||
type: fruit
|
||||
```
|
||||
|
||||
You can use dot notation to access nested structures. For example, to access the `name` of the first item, you would use the expression `.root.items[0].name`, which would return `apple`.
|
||||
|
||||
But lets see how we could find all the fruit under `items`
|
||||
|
||||
## Step 1: Initial Context
|
||||
The context starts at the root of the YAML document. In this case, the entire document is the initial context.
|
||||
|
||||
```
|
||||
root
|
||||
└── items
|
||||
├── name: apple
|
||||
│ type: fruit
|
||||
├── name: carrot
|
||||
│ type: vegetable
|
||||
└── name: banana
|
||||
type: fruit
|
||||
```
|
||||
|
||||
## Step 2: Splatting the Array
|
||||
Using the expression `.root.items[]`, we "splat" the items array. This means each element of the array becomes its own node in the context:
|
||||
|
||||
```
|
||||
Node 1: { name: apple, type: fruit }
|
||||
Node 2: { name: carrot, type: vegetable }
|
||||
Node 3: { name: banana, type: fruit }
|
||||
```
|
||||
|
||||
## Step 3: Filtering the Nodes
|
||||
Next, we apply a filter to select only the nodes where type is fruit. The expression `.root.items[] | select(.type == "fruit")` filters the nodes:
|
||||
|
||||
```
|
||||
Filtered Node 1: { name: apple, type: fruit }
|
||||
Filtered Node 2: { name: banana, type: fruit }
|
||||
```
|
||||
|
||||
## Step 4: Extracting a Field
|
||||
Finally, we extract the name field from the filtered nodes using `.root.items[] | select(.type == "fruit") | .name` This results in:
|
||||
|
||||
```
|
||||
apple
|
||||
banana
|
||||
```
|
||||
|
||||
## Simple assignment example
|
||||
|
||||
@ -44,7 +99,6 @@ a: dog
|
||||
b: dog
|
||||
```
|
||||
|
||||
|
||||
## Complex assignment, operator precedence rules
|
||||
|
||||
Just like math expressions - `yq` expressions have an order of precedence. The pipe `|` operator has a low order of precedence, so operators with higher precedence will get evaluated first.
|
||||
@ -73,7 +127,7 @@ name: sally
|
||||
fruit: mango
|
||||
```
|
||||
|
||||
To properly update this yaml, you will need to use brackets (think BODMAS from maths) and wrap the entire LHS:
|
||||
**Important**: To properly update this YAML, you must wrap the entire LHS in parentheses. Think of it like using brackets in math to ensure the correct order of operations.
|
||||
`(.[] | select(.name == "sally") | .fruit) = "mango"`
|
||||
|
||||
|
||||
@ -126,4 +180,4 @@ The assignment operator then copies across the value from the RHS to the value o
|
||||
```yaml
|
||||
a: 2
|
||||
b: thing
|
||||
```
|
||||
```
|
||||
319
operators/first.md
Normal file
319
operators/first.md
Normal file
@ -0,0 +1,319 @@
|
||||
# First
|
||||
|
||||
Returns the first matching element in an array, or first matching value in a map.
|
||||
|
||||
Can be given an expression to match with, otherwise will just return the first.
|
||||
|
||||
## First matching element from array
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
- a: banana
|
||||
- a: cat
|
||||
- a: apple
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq 'first(.a == "cat")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: cat
|
||||
```
|
||||
|
||||
## First matching element from array with multiple matches
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
- a: banana
|
||||
- a: cat
|
||||
b: firstCat
|
||||
- a: apple
|
||||
- a: cat
|
||||
b: secondCat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq 'first(.a == "cat")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: cat
|
||||
b: firstCat
|
||||
```
|
||||
|
||||
## First matching element from array with numeric condition
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
- a: 10
|
||||
- a: 100
|
||||
- a: 1
|
||||
- a: 101
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq 'first(.a > 50)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: 100
|
||||
```
|
||||
|
||||
## First matching element from array with boolean condition
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
- a: false
|
||||
- a: true
|
||||
b: firstTrue
|
||||
- a: false
|
||||
- a: true
|
||||
b: secondTrue
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq 'first(.a == true)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: true
|
||||
b: firstTrue
|
||||
```
|
||||
|
||||
## First matching element from array with null values
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
- a: null
|
||||
- a: cat
|
||||
- a: apple
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq 'first(.a != null)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: cat
|
||||
```
|
||||
|
||||
## First matching element from array with complex condition
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
- a: dog
|
||||
b: 7
|
||||
- a: cat
|
||||
b: 3
|
||||
- a: apple
|
||||
b: 5
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq 'first(.b > 4 and .b < 6)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: apple
|
||||
b: 5
|
||||
```
|
||||
|
||||
## First matching element from map
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
x:
|
||||
a: banana
|
||||
y:
|
||||
a: cat
|
||||
z:
|
||||
a: apple
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq 'first(.a == "cat")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: cat
|
||||
```
|
||||
|
||||
## First matching element from map with numeric condition
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
x:
|
||||
a: 10
|
||||
y:
|
||||
a: 100
|
||||
z:
|
||||
a: 101
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq 'first(.a > 50)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: 100
|
||||
```
|
||||
|
||||
## First matching element from nested structure
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
items:
|
||||
- a: banana
|
||||
- a: cat
|
||||
- a: apple
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.items | first(.a == "cat")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: cat
|
||||
```
|
||||
|
||||
## First matching element with no matches
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
- a: banana
|
||||
- a: cat
|
||||
- a: apple
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq 'first(.a == "dog")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
```
|
||||
|
||||
## First matching element from empty array
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
[]
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq 'first(.a == "cat")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
```
|
||||
|
||||
## First matching element from scalar node
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
hello
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq 'first(. == "hello")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
```
|
||||
|
||||
## First matching element from null node
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
null
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq 'first(. == "hello")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
```
|
||||
|
||||
## First matching element with string condition
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
- a: banana
|
||||
- a: cat
|
||||
- a: apple
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq 'first(.a | test("^c"))' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: cat
|
||||
```
|
||||
|
||||
## First matching element with length condition
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
- a: hi
|
||||
- a: hello
|
||||
- a: world
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq 'first(.a | length > 4)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: hello
|
||||
```
|
||||
|
||||
## First matching element from array of strings
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
- banana
|
||||
- cat
|
||||
- apple
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq 'first(. == "cat")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
cat
|
||||
```
|
||||
|
||||
## First matching element from array of numbers
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
- 10
|
||||
- 100
|
||||
- 1
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq 'first(. > 50)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
100
|
||||
```
|
||||
|
||||
## First element with no filter from array
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
- 10
|
||||
- 100
|
||||
- 1
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq 'first' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
10
|
||||
```
|
||||
|
||||
## First element with no filter from array of maps
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
- a: 10
|
||||
- a: 100
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq 'first' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: 10
|
||||
```
|
||||
|
||||
@ -56,6 +56,29 @@ will output
|
||||
sam
|
||||
```
|
||||
|
||||
## Get parents
|
||||
Match all parents
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a:
|
||||
b:
|
||||
c: cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.a.b.c | parents' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
- c: cat
|
||||
- b:
|
||||
c: cat
|
||||
- a:
|
||||
b:
|
||||
c: cat
|
||||
```
|
||||
|
||||
## N-th parent
|
||||
You can optionally supply the number of levels to go up for the parent, the default being 1.
|
||||
|
||||
|
||||
30
usage/xml.md
30
usage/xml.md
@ -319,7 +319,10 @@ Defaults to true
|
||||
Given a sample.xml file of:
|
||||
```xml
|
||||
<?xml version="1.0"?>
|
||||
<map xmlns="some-namespace" xmlns:xsi="some-instance" xsi:schemaLocation="some-url"></map>
|
||||
<map xmlns="some-namespace" xmlns:xsi="some-instance" xsi:schemaLocation="some-url">
|
||||
<item foo="bar">baz</item>
|
||||
<xsi:item>foobar</xsi:item>
|
||||
</map>
|
||||
|
||||
```
|
||||
then
|
||||
@ -329,13 +332,19 @@ yq --xml-keep-namespace=false '.' sample.xml
|
||||
will output
|
||||
```xml
|
||||
<?xml version="1.0"?>
|
||||
<map xmlns="some-namespace" xsi="some-instance" schemaLocation="some-url"></map>
|
||||
<map xmlns="some-namespace" xsi="some-instance" schemaLocation="some-url">
|
||||
<item foo="bar">baz</item>
|
||||
<item>foobar</item>
|
||||
</map>
|
||||
```
|
||||
|
||||
instead of
|
||||
```xml
|
||||
<?xml version="1.0"?>
|
||||
<map xmlns="some-namespace" xmlns:xsi="some-instance" xsi:schemaLocation="some-url"></map>
|
||||
<map xmlns="some-namespace" xmlns:xsi="some-instance" xsi:schemaLocation="some-url">
|
||||
<item foo="bar">baz</item>
|
||||
<xsi:item>foobar</xsi:item>
|
||||
</map>
|
||||
```
|
||||
|
||||
## Parse xml: keep raw attribute namespace
|
||||
@ -344,7 +353,10 @@ Defaults to true
|
||||
Given a sample.xml file of:
|
||||
```xml
|
||||
<?xml version="1.0"?>
|
||||
<map xmlns="some-namespace" xmlns:xsi="some-instance" xsi:schemaLocation="some-url"></map>
|
||||
<map xmlns="some-namespace" xmlns:xsi="some-instance" xsi:schemaLocation="some-url">
|
||||
<item foo="bar">baz</item>
|
||||
<xsi:item>foobar</xsi:item>
|
||||
</map>
|
||||
|
||||
```
|
||||
then
|
||||
@ -354,13 +366,19 @@ yq --xml-raw-token=false '.' sample.xml
|
||||
will output
|
||||
```xml
|
||||
<?xml version="1.0"?>
|
||||
<map xmlns="some-namespace" xmlns:xsi="some-instance" some-instance:schemaLocation="some-url"></map>
|
||||
<some-namespace:map xmlns="some-namespace" xmlns:xsi="some-instance" some-instance:schemaLocation="some-url">
|
||||
<some-namespace:item foo="bar">baz</some-namespace:item>
|
||||
<some-instance:item>foobar</some-instance:item>
|
||||
</some-namespace:map>
|
||||
```
|
||||
|
||||
instead of
|
||||
```xml
|
||||
<?xml version="1.0"?>
|
||||
<map xmlns="some-namespace" xmlns:xsi="some-instance" xsi:schemaLocation="some-url"></map>
|
||||
<map xmlns="some-namespace" xmlns:xsi="some-instance" xsi:schemaLocation="some-url">
|
||||
<item foo="bar">baz</item>
|
||||
<xsi:item>foobar</xsi:item>
|
||||
</map>
|
||||
```
|
||||
|
||||
## Encode xml: simple
|
||||
|
||||
Loading…
Reference in New Issue
Block a user