usando sed / awk para analisar tags XML

1

Para que fique registrado, passei vários dias trabalhando nisso sem sorte.

Estou trabalhando com arquivos XML com dados que contêm algo como o seguinte:

<row id="67581917031" name="4022" filesize="22425" file_content_id="67581868031" lastmodify_datetime="1187126570050" group_id="67581916031"/> <row id="254115371041" name="4022" filesize="49471" file_content_id="254115361041" lastmodify_datetime="1220512827666" group_id="253405951041"/> <row id="286104505041" name="4022" filesize="3802672" file_content_id="286104455041" lastmodify_datetime="1223348052489" group_id="286104504041"/> <row id="289541609041" name="4022" filesize="42235" file_content_id="264826268041" lastmodify_datetime="1223587308419" group_id="289541607041"/> <row id="306643757002" name="4022" filesize="392560" file_content_id="243411753011" lastmodify_datetime="1218251898489" group_id="67581916031"/> <row id="367316910041" name="4022" filesize="381083" file_content_id="367316830041" lastmodify_datetime="1232592570004" group_id="74169006021"/>

Se você olhar com cuidado, verá que dois desses registros têm o mesmo "nome" e "group_id". Eu estou tentando escrever um script que irá encontrar essas linhas e cuspir o ID da linha, nome e group_id em questão. Eu queria usar o sed para pegar no final de cada "linha" e inserir uma nova linha (\ n) para poder usar nl para imprimir o número de linhas, armazenar esse número em uma variável, em seguida, use um loop for para executar um comando awk para corresponder a cada id de linha, nome e group_id e, de alguma forma, verificar se o nome e group_id correspondem a qualquer outra linha e, se forem correspondentes, imprima o ID da linha e nome.

    
por Chris Olin 11.06.2013 / 20:20

1 resposta

2

Se você está procurando por aquelas linhas que têm o mesmo name AND group_id , você poderia fazer algo assim (supondo que você esteja em um * nix OS, você não diz na sua pergunta, você pode apenas cole isso diretamente na linha de comando):

sed 's#/>#/>\n#g' simple_file.xml |
        perl -ne 'if(/row id=.(.+?)\".+name=.(.+?)\".+group_id=.(.+?)\"/){ 
         push @{$k{join("\t",$2,$3)}},$1;} 
         END{ 
           foreach (keys(%k)){ 
            if($#{$k{$_}}>0){
                 print "$_\t",pop @{$k{$_}},"\n" 
          } }}' 

EXPLICAÇÃO:

  • sed 's#/>#/>\n#g' simple_file.xml : Adicione uma nova linha após cada entrada (após cada /> ) para facilitar a análise.
  • perl -ne : processa o arquivo, linha por linha
  • /row id= ... group_id=.(\d+)/; : use um regex (que geralmente é uma idéia ruim para arquivos HTML [X], você pode ter sangue de gatinhos fofos nas mãos) para obter as row_id , name e group_id , elas são salvas como $1 , $2 e $3 respectivamente.
  • push @{$k{join("\t",$2,$3)}},$1; : isso é um pouco mais complexo. Ele cria um hash de matrizes chamadas ( %k ) e, em seguida, usa join para conectar os name e group_id a uma guia. Finalmente, adiciona o row_id ao array. Em outras palavras, se seu row_id for 123 , seu name será 456 e seu group_id será 789 , isso criará um array e o salvará como o valor de hash %k para chave %código%.

  • O bloco 456 789 é executado uma vez, quando o restante do arquivo é processado. Ele vai passar por cada uma das chaves do hash (cujos valores são matrizes) e imprimir esses casos em que a matriz tem mais de uma entrada, em outras palavras, as duplicatas. A função END{} retorna o último elemento de um array, neste caso o pop .

Eu corri isto no seu exemplo e obtive esta saída:

4022    67581916031 306643757002
----    ----------  ------------
 |           |           |---------------> row id
 |           |---------------------------> group id
 |---------------------------------------> name

Se você não viu o link no segundo ponto, gostaria de enfatizar que você. Devemos. Nunca. Analise. [X] HTML Com. Regular. Expressões.

    
por 11.06.2013 / 21:00

Tags