opendatasicilia / tansignari

"T'ansignari e t'appeddiri"
http://tansignari.opendatasicilia.it
Creative Commons Attribution 4.0 International
18 stars 10 forks source link

[GIS] file XML come estrarre alcuni dati #50

Closed pigreco closed 5 years ago

pigreco commented 5 years ago

Ho un file XML che rappresenta la tematizzazione (metodo categorizzato) di un layer (esempio shapefile regioni ISTAT) e vorrei estrarre due dati importanti per il mio caso:

  1. la regione;
  2. il colore di riempimento espresso in rgba;

Ho provato usando, in LibreCalc, questa espressione

=FILTRO.XML(‪C:\Users\pigre\Desktop\tema.xml;"//categories/category/value/")

ma ottengo un errore

image

vorrei ottenere una tabella CSV cosi fatta:

regione colore
Sicilia 210,214,92,255
Sardegna 234,16,38,255

allego file XML

tema.zip

aborruso commented 5 years ago

EDIT: corretto join con Miller (vedi errore qui)

Caro @pigreco una risposta di corsa. A riga di comando un tool è xmlstarlet, da accoppiare a XPATH. Questa prima è più facile, ma non ce l'ho pronta in canna.

Stasera una soluzione sporca che passa da xq (che è dentro yq), che consente di fare query a un XML, come se fosse un file JSON. Non riesco però stasera a dettagliare bene.

Con

<tema.xml xq -r '.qgis["renderer-v2"].symbols.symbol[]|[.["@name"],.layer.prop[1]["@v"]]|@csv' >./idColori.csv

estrai

"0","232,193,76,255"
"1","48,218,227,255"
"10","231,108,155,255"
"11","237,177,124,255"
"12","63,175,231,255"
"13","210,214,92,255"
"14","234,16,38,255"
"15","239,110,81,255"
"16","50,235,192,255"
"17","160,107,220,255"
"18","98,66,238,255"
"19","34,233,131,255"
"2","224,59,169,255"
"3","163,225,124,255"
"4","162,15,210,255"
"5","68,239,48,255"
"6","179,235,59,255"
"7","219,21,209,255"
"8","18,39,233,255"
"9","120,204,137,255"

Con

<tema.xml xq -r '.qgis["renderer-v2"].categories.category[]|[.["@symbol"],.["@value"]]|@csv' >./idRegioni.csv

estrai

"0","Abruzzo"
"1","Basilicata"
"2","Calabria"
"3","Campania"
"4","Emilia-Romagna"
"5","Friuli Venezia Giulia"
"6","Lazio"
"7","Liguria"
"8","Lombardia"
"9","Marche"
"10","Molise"
"11","Piemonte"
"12","Puglia"
"13","Sardegna"
"14","Sicilia"
"15","Toscana"
"16","Trentino-Alto Adige"
"17","Umbria"
"18","Valle d'Aosta"
"19","Veneto"

E poi basta fare un join. Con Miller è

mlr --csv --implicit-csv-header --headerless-csv-output  join  -j 1 --lp colori --rp regioni -f idColori.csv idRegioni.csv >./out.csv

Che ti da

0,"232,193,76,255",Abruzzo
1,"48,218,227,255",Basilicata
2,"224,59,169,255",Calabria
3,"163,225,124,255",Campania
4,"162,15,210,255",Emilia-Romagna
5,"68,239,48,255",Friuli Venezia Giulia
6,"179,235,59,255",Lazio
7,"219,21,209,255",Liguria
8,"18,39,233,255",Lombardia
9,"120,204,137,255",Marche
10,"231,108,155,255",Molise
11,"237,177,124,255",Piemonte
12,"63,175,231,255",Puglia
13,"210,214,92,255",Sardegna
14,"234,16,38,255",Sicilia
15,"239,110,81,255",Toscana
16,"50,235,192,255",Trentino-Alto Adige
17,"160,107,220,255",Umbria
18,"98,66,238,255",Valle d'Aosta
19,"34,233,131,255",Veneto
pigreco commented 5 years ago

@aborruso ho installato yq

sudo add-apt-repository ppa:rmescandon/yq
sudo apt update
sudo apt install yq -y

preso da qui: https://mikefarah.github.io/yq/

ma lanciando

<tema.xml xq -r '.qgis["renderer-v2"].symbols.symbol[]|[.["@name"],.layer.prop[1]["@v"]]|@csv' >./idColori.csv

ho questo messaggio:

image

pigreco commented 5 years ago

yq si installa cosi:

pip3 install yq


poi, noto che il join si mangia la prima cifra del codice colore:

image

aborruso commented 5 years ago

@pigreco grazie ho modificato il join, errore mio

pigreco commented 5 years ago

@aborruso grazie per il tempo dedicato e la rapidità della soluzione, ho messo tutto assieme per creare un piccolo script da lanciare, per esempio, in win 10 usando bash ubuntu:

#!/bin/bash
set -x

<tema.xml xq -r '.qgis["renderer-v2"].symbols.symbol[]|[.["@name"],.layer.prop[1]["@v"]]|@csv' >./idColori.csv
<tema.xml xq -r '.qgis["renderer-v2"].categories.category[]|[.["@symbol"],.["@value"]]|@csv' >./idRegioni.csv
mlr --csv --implicit-csv-header --headerless-csv-output  join  -j 1 --lp colori --rp regioni -f idColori.csv idRegioni.csv >./out.csv

rm idColori.csv
rm idRegioni.csv

image

funzione benissimo.

Grazie a breve aggiungo ricetta

pigreco commented 5 years ago

Lo script di sopra è valido per il metodo categorizzato, per il metodo graduato lo script è il seguente:

#!/bin/bash
set -x

<tema_range.xml xq -r '.qgis["renderer-v2"].symbols.symbol[]|[.["@name"],.layer.prop[1]["@v"]]|@csv' >./idColori.csv
<tema_range.xml xq -r '.qgis["renderer-v2"].ranges.range[]|[.["@symbol"],.["@label"]]|@csv' >./idRange.csv
mlr --csv --implicit-csv-header --headerless-csv-output  join  -j 1 --lp colori --rp regioni -f idColori.csv idRange.csv >./out_range.csv

rm idColori.csv
rm idRange.csv

testato con ottimi risultati :-)

aborruso commented 5 years ago

Edit: corretto XPATH colori

Con XPATH è più leggibile e diretto (nasce per lavorare su XML). Un utility a riga di comando è xmlstarlet (che si installa con sudo apt-get install xmlstarlet)

Con

<tema.xml xmlstarlet fo -D | xmlstarlet sel -T -t -m "//category" -v $'concat(@symbol,"\t",@value)' -n >./idRegioni.tsv

si ottiene

0       Abruzzo
1       Basilicata
2       Calabria
3       Campania
4       Emilia-Romagna
5       Friuli Venezia Giulia
6       Lazio
7       Liguria
8       Lombardia
9       Marche
10      Molise
11      Piemonte
12      Puglia
13      Sardegna
14      Sicilia
15      Toscana
16      Trentino-Alto Adige
17      Umbria
18      Valle d'Aosta
19      Veneto

Con

<tema.xml xmlstarlet fo -D | xmlstarlet sel -T -t -m "//symbols/symbol" -v $'concat(@name,"\t",layer/prop[@k="color"]/@v)' -n >./idColori.tsv

si ottiene

0       232,193,76,255
1       48,218,227,255
10      231,108,155,255
11      237,177,124,255
12      63,175,231,255
13      210,214,92,255
14      234,16,38,255
15      239,110,81,255
16      50,235,192,255
17      160,107,220,255
18      98,66,238,255
19      34,233,131,255
2       224,59,169,255
3       163,225,124,255
4       162,15,210,255
5       68,239,48,255
6       179,235,59,255
7       219,21,209,255
8       18,39,233,255
9       120,204,137,255
0       183,72,75,255

E poi sui due TSV si fa il join.

La query //prop[@k="color"]/@v, corrisponde al valore della proprietà v del tag prop che ha color come valore della proprietà k. Ovvero cerca righe come questa <prop v="210,214,92,255" k="color"/>

pigreco commented 5 years ago

@aborruso bella anche questa soluzione

domanda:

  1. aggiungo alla ricetta
  2. realizzo altra ricetta usando il metodo graduato al posto del categorizzato
aborruso commented 5 years ago

Aggiungerei alla ricetta

pigreco commented 5 years ago

@aborruso ho provato a fare il JOIN con miller

mlr --tsv --implicit-tsv-header --headerless-tsv-output  join  -j 1 --lp colori --rp regioni -f idColori.tsv idRegioni.tsv >./out_regioni_xpath.tsv

il file di output è vuoto: image

aborruso commented 5 years ago

@pigreco prova con

mlr --tsv --implicit-csv-header --headerless-csv-output  join  -j 1 --lp colori --rp regioni -f idColori.tsv idRegioni.tsv

Nel file XML mi sembra che ci siano due symbol con name 0. È corretto?

pigreco commented 5 years ago

Buongiorno @aborruso funziona ma, come osservi, nel file di output, ci sono sue righe con valore 0

ho analizzato il file XML: il primo name="0" si trova sotto <symbols> il secondo sotto <source-symbol>

image

aborruso commented 5 years ago

@pigreco grazie, mi hai fatto vedere l'errore. Nella query sui colori ho impostato correttamente la gerarchia e modificato //symbol in //symbols/symbol.

Ho modificato il messaggio di sopra

pigreco commented 5 years ago

@aborruso grazie per il tempo dedicato e la duplice soluzione, ho messo tutto assieme per creare un piccolo script da lanciare, per esempio, in win 10 usando bash ubuntu:

#!/bin/bash
set -x

<tema.xml xmlstarlet fo -D | xmlstarlet sel -T -t -m "//symbols/symbol" -v $'concat(@name,"\t",layer/prop[@k="color"]/@v)' -n >./idColori.tsv
<tema.xml xmlstarlet fo -D | xmlstarlet sel -T -t -m "//category" -v $'concat(@symbol,"\t",@value)' -n >./idRegioni.tsv
mlr --tsv --implicit-csv-header --headerless-csv-output  join  -j 1 --lp colori --rp regioni -f idColori.tsv idRegioni.tsv >./out_regioni_xpath.tsv

rm idColori.tsv
rm idRegioni.tsv

funziona benissimo.

Aggiungo lo script alla ricetta

aborruso commented 5 years ago

Aggiungo la stessa cosa, ma fatta con un foglio elettronico https://docs.google.com/spreadsheets/d/1tjXYrhP2nggPxML3Vay2Ycab7ikACQ95scRHLjo_GYc/edit#gid=0