问题
I'm new to jq
and I have the following code to obtain tabulated the values for each element called Abc
:
["Abc"], ( .. | objects | select(has("Abc")) | [.["Abc"]] ) | @tsv
This is the current output I get:
"Abc"
"4"
"2"
"1"
"9"
"3"
"2"
"4"
"9"
I would like to add 4 columns to the left to show for each Abc
value the corresponding page, row and column. Additionally if possible as first column add a counter from 1 to number of "Abc" elements.
Below I show the current output, compared with the desired output and the structure of the Json file in order to clarify:
The input Json file is below:
{
"document": {
"page": [
{
"@index": "0",
"image": {
"Abc": "4"
}
},
{
"@index": "1",
"row": [
{
"column": [
{
"text": {
"Abc": "2"
}
}
]
},
{
"column": [
{
"text": {
"Abc": "1"
}
},
{
"text": {
"Abc": "9"
}
}
]
},
{
"column": [
{
"text": {
"Abc": "3"
}
}
]
}
]
},
{
"@index": "2",
"row": [
{
"column": [
{
"text": {
"Abc": "2"
}
}
]
},
{
"column": [
{
"text": {
"Abc": "4"
}
},
{
"text": {
"Abc": "9"
}
}
]
}
]
}
]
}
}
I hope someone could help me. Thanks in advance.
回答1:
The following solution uses paths
and has several advantages, including brevity, simplicity, and that it can easily be adapted to a handle data that is in a different format.
For clarity, we begin by defining a function that adds the row numbers:
# add a sequential id, starting at 1
def tsvRows(s):
foreach s as $s (0; .+1; [.] + $s)
| @tsv;
(["counter", "page", "row", "column", "Abc"] | @tsv),
tsvRows(paths as $p
| select($p[-1] == "Abc")
| getpath($p) as $v
| $p
| .[2] as $page
| (if .[3] == "row" then .[4] else null end) as $row
| (if .[5] == "column" then .[6] else null end) as $column
| [$page, $row, $column, $v] )
回答2:
The irregularity of the input data makes the requirements a little opaque, but the following produces the desired output.
["counter", "page", "row", "column", "Abc"],
(foreach (.document.page[] | objects) as $page ({page: -1, counter: 0};
.page += 1
| if ($page | (has("image") and (.image|has("Abc"))))
then
.counter +=1
| .out = [.counter, .page, null, null, ($page|.image.Abc)]
else foreach ($page | .row[]?) as $row (.row=-1;
.row += 1
| foreach ($row | .column[]) as $column (.column=-1;
.column +=1
| foreach ($column | .text | objects) as $x (.;
.counter += 1
| .out = [.counter, .page, .row, .column, $x["Abc"]]
; . )
; . )
; . )
end
; .out )
)
| @tsv
Output
Specifically, with the -r command-line option, the output produced from the given input is as follows (tabs included):
counter page row column Abc
1 0 4
2 1 0 0 2
3 1 1 0 1
4 1 1 1 9
5 1 2 0 3
6 2 0 0 2
7 2 1 0 4
8 2 1 1 9
回答3:
even though the question was for jq, for those who interested in the alternative solutions, here's one based on a walk-path unix utility jtc:
bash $ <file.json jtc -w' ' -T0 -w'[0][page][0]<p>k<Abc>l' -T'"{p}\t\t\t{}"' -w'[0][page][1:]<p>k[row][:]<r>k[column][:]<c>k<Abc>l' -T'"{p}\t{r}\t{c}\t{}"' -j | jtc -qqw' ' -T'"#\tpage\trow\tcolumn\tAbc"' -w'[1:]<#>k<v>v' -T'"{#}\t{v}"'
# page row column Abc
1 0 4
2 1 0 0 2
3 1 1 0 1
4 1 1 1 9
5 1 2 0 3
6 2 0 0 2
7 2 1 0 4
8 2 1 1 9
bash $
in the first jtc
call, first dummy walk-path (-w' '
) is need only for purposes of offsetting start index to 1
(otherwise column #
would be displayed starting from idx 0
)
second walk processes the first page (0
) only,
third walk-path processes the rest of JSON.
PS> Disclosure: I'm the creator of the jtc
- shell cli tool for JSON operations
来源:https://stackoverflow.com/questions/56386521/relate-elements-in-table-form-from-json-file-with-jq