Portál AbcLinuxu, 20. prosince 2025 23:39
<polozky>
<polozka>
<jmeno>prvni</jmeno>
<barva>cervena</barva>
</polozka>
<polozka>
<jmeno>druha</jmeno>
<barva>zelena</barva>
</polozka>
<polozka>
<jmeno>treti</jmeno>
<barva>modra</barva>
</polozka>
</polozky>
naplnit pole:
jmeno[0]=prvni jmeno[1]=druha jmeno[2]=treti barva[0]=cervena barva[1]=zelena barva[2]=modraaktualne to delam pres spocitani polozek a pak rozdelit/parsovat v poctu cyklu pres grep,tac,cat,sed...
To by použít šlo. Pro zajímavost přikládám Makefile pro stažení toho XML z tvého komentáře:
all: položky.xml .PHONY: clean clean: rm -f diskuse.html rm -f položky.xml diskuse.html: wget -O $@ --xattr https://www.abclinuxu.cz/zpravicky/relational-pipes-v0.18/diskuse#8 položky.xml: diskuse.html cat $(<) \ | relpipe-in-htmltable \ --relation 'pre' \ --records '//pre[1]' \ --attribute 'pre' string '.' \ | relpipe-out-nullbyte | tr \\0 \\n \ > $@
To z HTML stránky extrahuje obsah prvního <pre/> elementu:
<polozky>
<polozka>
<jmeno>prvni</jmeno>
<barva>cervena</barva>
</polozka>
<polozka>
<jmeno>druha</jmeno>
<barva>zelena</barva>
</polozka>
<polozka>
<jmeno>treti</jmeno>
<barva>modra</barva>
</polozka>
</polozky>
A potom to načtení XML a naplnění do proměnných:
#!/bin/bash
make položky.xml
read_nullbyte() { local IFS=; for v in "$@"; do export "$v"; read -r -d '' "$v"; done }
jmeno=();
barva=();
while read_nullbyte jmeno barva; do
jmeno+=("$jmeno");
barva+=("$barva");
done < <(cat položky.xml \
| relpipe-in-xmltable \
--relation 'položka' \
--records '/polozky/polozka' \
--attribute 'jméno' string 'jmeno' \
--attribute 'barva' string 'barva' \
| relpipe-out-nullbyte)
for j in ${jmeno[@]}; do echo "jméno: $j"; done
for b in ${barva[@]}; do echo "barva: $b"; done
Případně bez proměnných a rovnou nad každou položkou volat nějaký kód:
#!/bin/bash
make položky.xml
read_nullbyte() { local IFS=; for v in "$@"; do export "$v"; read -r -d '' "$v"; done }
cat položky.xml \
| relpipe-in-xmltable \
--relation 'položka' \
--records '/polozky/polozka' \
--attribute 'jméno' string 'jmeno' \
--attribute 'barva' string 'barva' \
| relpipe-out-nullbyte \
| while read_nullbyte j b; do
echo "jméno: $j";
echo "barva: $b";
done
Vypíše to:
make: „položky.xml“ je aktuální. jméno: prvni jméno: druha jméno: treti barva: cervena barva: zelena barva: modra
P.S. k té funkci read_nullbyte(): ptal jsem se v konferenci Bashe, jestli by to šlo nějak lépe: Help-bash] Readig multiple null-separated values, ale asi nešlo. Přišlo by mi užitečné, kdyby to byla součást shellu resp. jeho funkce read.
slo by zaroven vytahnout i info z vnorene podvetve? zkousel sem pridat dalsi sekci --records i dalsi --relation ale nedarilo se, pri --help na me rve ze ne, a ze zdrojaku sem se nezorientoval :)
<polozky>
<polozka>
<jmeno>prvni</jmeno>
<barva>cervena</barva>
<jmeno>prvni</jmeno>
<info>
<vyska>100</vyska>
<sirka>50</sirka>
</info>
</polozka>
<polozka>
<jmeno>druha</jmeno>
<barva>zelena</barva>
<info>
<vyska>200</vyska>
<sirka>60</sirka>
</info>
</polozka>
<polozka>
<jmeno>treti</jmeno>
<barva>modra</barva>
<info>
<vyska>300</vyska>
<sirka>70</sirka>
</info>
</polozka>
</polozky>
naplnit pole:
jmeno[0]=prvni jmeno[1]=druha jmeno[2]=treti barva[0]=cervena barva[1]=zelena barva[2]=modra vyska[0]=100 vyska[1]=200 vyska[2]=300 sirka[0]=50 sirka[1]=60 sirka[2]=70
Pořádnou dokumentaci teprve píšu, zatím jsou jen ty příklady a bash-completion skripty.
Do toho --attribute se píše název (jak se to má jmenovat na výstupu), typ a XPath výraz – ve kterém se dá jednoduše odkázat na vnořený element (dá se toho tam dělat i mnohem víc, volat různé funkce atd.). Takže v tomhle případě by to bylo jen info/vyska a info/sirka:
while read_nullbyte jmeno barva vyska sirka; do
jmeno+=("$jmeno");
barva+=("$barva");
vyska+=("$vyska");
sirka+=("$sirka");
done < <(cat položky.xml \
| relpipe-in-xmltable \
--relation 'položka' \
--records '/polozky/polozka' \
--attribute 'jméno' string 'jmeno' \
--attribute 'barva' string 'barva' \
--attribute 'výška' string 'info/vyska' \
--attribute 'šířka' string 'info/sirka' \
| relpipe-out-nullbyte)
for j in ${jmeno[@]}; do echo "jméno: $j"; done
for b in ${barva[@]}; do echo "barva: $b"; done
for v in ${vyska[@]}; do echo "výška: $v"; done
for s in ${sirka[@]}; do echo "šířka: $s"; done
vypíše to:
jméno: prvni jméno: druha jméno: treti barva: cervena barva: zelena barva: modra výška: 100 výška: 200 výška: 300 šířka: 50 šířka: 60 šířka: 70
Taky se někdy může hodit převést stromovou strukturu na plochou.
#!/bin/bash
soubor="položky.xml"
make "$soubor"
xml() { cat "$soubor"; }
# xml() { cat ../yamltable/netplan.yaml | yaml2xml; }
plocha() {
relpipe-in-xmltable \
--relation 'data' \
--records '//text()[normalize-space() != ""]' \
--attribute 'key' string '..' --mode xpath \
--attribute 'value' string '.'
}
tecky() {
relpipe-tr-sed \
--relation '.+' \
--attribute 'key' \
--value '[/\[\]]+' \
--replacement '.' \
--attribute 'key' \
--value '^\.[^\.]+\.' \
--replacement ''
}
properties() {
relpipe-out-ini \
--relation '.*' \
--writer-option dialect java-properties \
--writer-option key-value-separator ' = '
}
xml | plocha | relpipe-out-tabular
xml | plocha | tecky | properties
Výstup:
data: ╭────────────────────────────────┬────────────────╮ │ key (string) │ value (string) │ ├────────────────────────────────┼────────────────┤ │ /polozky/polozka[1]/jmeno │ prvni │ │ /polozky/polozka[1]/barva │ cervena │ │ /polozky/polozka[1]/info/vyska │ 100 │ │ /polozky/polozka[1]/info/sirka │ 50 │ │ /polozky/polozka[2]/jmeno │ druha │ │ /polozky/polozka[2]/barva │ zelena │ │ /polozky/polozka[2]/info/vyska │ 200 │ │ /polozky/polozka[2]/info/sirka │ 60 │ │ /polozky/polozka[3]/jmeno │ treti │ │ /polozky/polozka[3]/barva │ modra │ │ /polozky/polozka[3]/info/vyska │ 300 │ │ /polozky/polozka[3]/info/sirka │ 70 │ ╰────────────────────────────────┴────────────────╯ Record count: 12
polozka.1.jmeno = prvni polozka.1.barva = cervena polozka.1.info.vyska = 100 polozka.1.info.sirka = 50 polozka.2.jmeno = druha polozka.2.barva = zelena polozka.2.info.vyska = 200 polozka.2.info.sirka = 60 polozka.3.jmeno = treti polozka.3.barva = modra polozka.3.info.vyska = 300 polozka.3.info.sirka = 70
Případně pro ten netplan.yaml:
data: ╭────────────────────────────────────────────────────┬──────────────────╮ │ key (string) │ value (string) │ ├────────────────────────────────────────────────────┼──────────────────┤ │ /yaml/network/version │ 2 │ │ /yaml/network/ethernets/enp84s0/dhcp4 │ false │ │ /yaml/network/ethernets/enp84s0/dhcp6 │ false │ │ /yaml/network/ethernets/enp84s0/accept-ra │ false │ │ /yaml/network/bridges/br0/interfaces[1] │ enp84s0 │ │ /yaml/network/bridges/br0/interfaces[2] │ eth0 │ │ /yaml/network/bridges/br0/addresses │ 192.168.1.101/24 │ │ /yaml/network/bridges/br0/gateway4 │ 192.168.1.1 │ │ /yaml/network/bridges/br0/nameservers/addresses[1] │ 192.168.1.10 │ │ /yaml/network/bridges/br0/nameservers/addresses[2] │ 192.168.1.11 │ │ /yaml/network/bridges/br0/mtu │ 1500 │ │ /yaml/network/bridges/br0/parameters/stp │ true │ │ /yaml/network/bridges/br0/parameters/forward-delay │ 4 │ │ /yaml/network/bridges/br0/dhcp4 │ false │ │ /yaml/network/bridges/br0/dhcp6 │ false │ │ /yaml/network/bridges/br0/accept-ra │ false │ ╰────────────────────────────────────────────────────┴──────────────────╯ Record count: 16
network.version = 2 network.ethernets.enp84s0.dhcp4 = false network.ethernets.enp84s0.dhcp6 = false network.ethernets.enp84s0.accept-ra = false network.bridges.br0.interfaces.1. = enp84s0 network.bridges.br0.interfaces.2. = eth0 network.bridges.br0.addresses = 192.168.1.101/24 network.bridges.br0.gateway4 = 192.168.1.1 network.bridges.br0.nameservers.addresses.1. = 192.168.1.10 network.bridges.br0.nameservers.addresses.2. = 192.168.1.11 network.bridges.br0.mtu = 1500 network.bridges.br0.parameters.stp = true network.bridges.br0.parameters.forward-delay = 4 network.bridges.br0.dhcp4 = false network.bridges.br0.dhcp6 = false network.bridges.br0.accept-ra = false
Na té stránce netplan.yaml je i ukázané, jak se dá vygenerovat víc relací z jednoho XML (--relation tam může být víckrát, --records je tam u každé jen jednou).
aktualne to delam pres spocitani polozek a pak rozdelit/parsovat v poctu cyklu pres grep,tac,cat,sed...To by snad mělo jít udělat přes nějaký 'standardní' XML tooling ne?
#!/bin/bash
IFS=$'\n'
jmeno=( $(xmllint --xpath 'polozky/polozka/jmeno/text()' xml.xml) )
barva=( $(xmllint --xpath 'polozky/polozka/barva/text()' xml.xml) )
echo ${jmeno[@]}
echo ${barva[@]}
Tiskni
Sdílej:
ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.