Extraia e exclua a primeira ocorrência da tag XML várias vezes

1

Eu tenho um arquivo XML de tamanho pequeno. Eu tenho sido fornecido com isso e tudo que eu preciso fazer é extrair alguns valores entre as tags XML. Desde que eu não tenho o utilitário XML parser disponível em minhas máquinas. Eu estou procurando um método alternativo.

Para começar, há uma tag XML <capacity> </capacity > que repete n número de tempo no arquivo XML e entre essas tags XML também existem muitas outras tags diferentes.

Eu tenho que pegar cada ocorrência da tag <capacity> </capacity> XML separadamente e então analisar isso e extrair os valores abaixo deles.

<subcolumns><capacity><name>45.90</name>
<index>0</index>
<value_type>String</value_type>
<ignore_case_flag>1</ignore_case_flag>
<hidden_flag>0</hidden_flag>
<exclude_from_parse_flag>1</exclude_from_parse_flag>
</capacity>
<capacity><name>57.09</name>
<index>1</index>
<value_type>String</value_type>
<ignore_case_flag>1</ignore_case_flag>
<hidden_flag>0</hidden_flag>
<exclude_from_parse_flag>1</exclude_from_parse_flag>
</capacity>
<capacity><name>55</name>
<index>2</index>
<value_type>String</value_type>
<ignore_case_flag>1</ignore_case_flag>
<hidden_flag>0</hidden_flag>
<exclude_from_parse_flag>1</exclude_from_parse_flag>
</capacity>
</subcolumns>

Portanto, a lógica que pensei foi encontrar a primeira ocorrência de uma tag <capacity> </capacity> XML e imprimi-la em um arquivo temporário e, em seguida, excluir essa primeira ocorrência.

<capacity><name>45.90</name>
<index>0</index>
<value_type>String</value_type>
<ignore_case_flag>1</ignore_case_flag>
<hidden_flag>0</hidden_flag>
<exclude_from_parse_flag>1</exclude_from_parse_flag>
</capacity>

Daqui em diante, quando isso for feito pela segunda vez, o novo par de tags <capacity> </capacity> XML será levado em consideração. Portanto, isso deve ser repetido várias vezes até que a última tag <capacity> </capacity> seja encontrada. E cada vez que essa parte é extraída, os dados estarão mudando e isso pode ser extraído.

Agora, tudo que desejo é selecionar a primeira ocorrência da tag <capacity> </capacity> XML no arquivo XML principal & imprima-o no arquivo temporário e exclua essa parte.

E isso é o que eu tentei e nada funcionou para mim.

sed -n '2,${/<capacity>\(.*\)<\/capacity>//p;q;}' "<input XML file>" >> temp.txt

Minha ideia adicional é pegar esse arquivo temporário para processar e extrair os valores que preciso sob as tags capacity . Para o qual eu já escrevi a lógica e está funcionando bem.

    
por ramp 05.06.2017 / 17:42

3 respostas

5

O uso de analisadores XML é o caminho certo para manipular documentos XML.

solução xmlstarlet :

xmlstarlet sel -t -c '//capacity[1]' -n yourxml > temp.txt 
&& xmlstarlet ed -d '//capacity[1]' yourxml > tmp.xml && mv tmp.xml yourxml 
cat temp.txt
<capacity><name>45.90</name>
<index>0</index>
<value_type>String</value_type>
<ignore_case_flag>1</ignore_case_flag>
<hidden_flag>0</hidden_flag>
<exclude_from_parse_flag>1</exclude_from_parse_flag>
</capacity>
  • xmlstarlet sel -t -c '//capacity[1]' -n yourxml > temp.txt - extrai a primeira declaração de tag capacity e redireciona a saída para temp.txt

  • xmlstarlet ed -d '//capacity[1]' yourxml > tmp.xml - exclui a primeira tag capacity do documento (via -d delete action) e redireciona o conteúdo do documento modificado para o arquivo temporário tmp.xml

  • mv tmp.xml yourxml - substitua o documento xml inicial pela versão modificada

por 05.06.2017 / 17:59
2

Como você não tem um analisador xml, experimente este com o gnu awk:

$ awk -v RS="<subcolumns>|</capacity>" 'NR==2{gsub(/^\n/,"");print $0 RT;exit}' file.xml
<capacity><name>45.90</name>
<index>0</index>
<value_type>String</value_type>
<ignore_case_flag>1</ignore_case_flag>
<hidden_flag>0</hidden_flag>
<exclude_from_parse_flag>1</exclude_from_parse_flag>
</capacity>

Por que isso funciona:
no awk você pode definir um registro personalizado / separador de linha. Em nosso exemplo, usamos <subcolumns> ou </capacity>

Como resultado, com um separador de registro personalizado, podemos alcançar este formato:

$ awk -v RS="<subcolumns>|</capacity>" '{gsub(/^\n/,"");print NR,$0 RT}' file.xml
1 <subcolumns>
2 <capacity><name>45.90</name>
<index>0</index>
<value_type>String</value_type>
<ignore_case_flag>1</ignore_case_flag>
<hidden_flag>0</hidden_flag>
<exclude_from_parse_flag>1</exclude_from_parse_flag>
</capacity>
3 <capacity><name>57.09</name>
<index>1</index>
<value_type>String</value_type>
<ignore_case_flag>1</ignore_case_flag>
<hidden_flag>0</hidden_flag>
<exclude_from_parse_flag>1</exclude_from_parse_flag>
</capacity>
4 <capacity><name>55</name>
<index>2</index>
<value_type>String</value_type>
<ignore_case_flag>1</ignore_case_flag>
<hidden_flag>0</hidden_flag>
<exclude_from_parse_flag>1</exclude_from_parse_flag>
</capacity>
5 </subcolumns>

PS: NR = número ou registro / linha. RT = Record Separator usado.

Assim, você pode imprimir qualquer bloco <capacity></capacity> ajustando o número NR:

$ awk -v RS="<subcolumns>|</capacity>" 'NR==4{gsub(/^\n/,"");print $0 RT}'
<capacity><name>55</name>
<index>2</index>
<value_type>String</value_type>
<ignore_case_flag>1</ignore_case_flag>
<hidden_flag>0</hidden_flag>
<exclude_from_parse_flag>1</exclude_from_parse_flag>
</capacity>

Consequentemente, se você precisar pular uma seção <capacity> (ou seja, a seção da primeira capacidade), basta fazer:

$ awk -v RS="<subcolumns>|</capacity>" '{gsub(/^\n/,"")}NR!=2{print $0 RT}'
<subcolumns>
<capacity><name>57.09</name>
<index>1</index>
<value_type>String</value_type>
<ignore_case_flag>1</ignore_case_flag>
<hidden_flag>0</hidden_flag>
<exclude_from_parse_flag>1</exclude_from_parse_flag>
</capacity>
<capacity><name>55</name>
<index>2</index>
<value_type>String</value_type>
<ignore_case_flag>1</ignore_case_flag>
<hidden_flag>0</hidden_flag>
<exclude_from_parse_flag>1</exclude_from_parse_flag>
</capacity>
</subcolumns>
    
por 05.06.2017 / 21:19
0
chunk=2; # specify the tag chunk number here which must be > 0
perl -l -0777ne "print((m{(<capacity>.*?</capacity>)}sg)[${chunk:-1}-1])" yourxmlfile

Resultados

<capacity><name>57.09</name>
<index>1</index>
<value_type>String</value_type>
<ignore_case_flag>1</ignore_case_flag>
<hidden_flag>0</hidden_flag>
<exclude_from_parse_flag>1</exclude_from_parse_flag>
</capacity>
    
por 05.06.2017 / 23:27