Procura substituir no arquivo XML com sed ou awk

3

Portanto, tenho uma tarefa em que tenho de manipular um arquivo XML por meio de um script de shell bash.

Aqui estão os passos:

  1. Consultar arquivo XML para um valor.
  2. Pegue o valor e faça referência cruzada para encontrar um novo valor em uma lista.
  3. Substitua o valor de um elemento diferente pelo novo valor.

Aqui está uma amostra do XML com informações não essenciais removidas:

<fmreq:fileManagementRequestDetail xmlns:fmreq="http://foobar.com/filemanagement">
      <fmreq:property>
         <fmreq:name>form_category_cd</fmreq:name>
         <fmreq:value>Memos</fmreq:value>
      </fmreq:property>
      <fmreq:property>
         <fmreq:name>object_name</fmreq:name>
         <fmreq:value>Correspondence</fmreq:value>
      </fmreq:property>
</fmreq:fileManagementRequestDetail>

Eu tenho que obter o valor do elemento de valor em object_name, fazer referência cruzada e, em seguida, substituir o valor no elemento de valor form_category_cd pelo novo valor:

Então, se object_name - > value é Correspondência, em seguida, o form_category_cd - > valor pode precisar ser YYZ.

Aqui está o comentário, só posso usar as ferramentas disponíveis no nosso servidor, pois o nosso grupo de operações está nos restringindo às ferramentas disponíveis. Foi uma luta para obter xmllint atualizado e, em seguida, foi rejeitado. Eu estou em uma versão que não suporta - xpath, que acredita em mim é difícil em um bom dia. Além disso, a versão que tenho disponível não suporta namespaces, então o xmllint está fora.

Eu tentei o sed, mas parece que ele não gosta do meu regex, embora todos os testadores que eu tente funcionem bem.

Regex:

(<fmreq\:name>object_name<\/fmreq\:name>)(?:\n\s*)(<fmreq\:value>)(.*)(<\/fmreq\:value>)

Eu preciso do grupo 3, mas o sed não retornará. Em vez disso, ele retorna todo o conteúdo do arquivo XML.

sed -e 's/\(<fmreq\:name>object_name<\/fmreq\:name>\)\(?:\n\s*\)\(<fmreq\:value>\)\(.*\)\(<\/fmreq\:value>\)//' < c3.xml 

Eu não estou tão familiarizado com o awk / gawk, então estou lutando para descobri-los e também, mas estou aberto a eles se uma solução puder ser encontrada.

Adoraria ter uma solução awk / gawk só para deixar o chefe feliz, já que ele é um velho fã do awk, mas eu vou pegar o que eu conseguir enquanto estou perplexo.

Mais uma vez, preciso usar as ferramentas disponíveis e não posso instalar nada de novo.

    
por Bob Lyman 14.10.2017 / 23:11

2 respostas

2

Acho que há alguns problemas no seu comando sed :

  • Você não usa a opção -n , portanto, por padrão, sed apenas imprime cada linha de entrada na saída (possivelmente modificada por um comando sed ).

  • Você não precisa do redirecionamento < c3.xml , porque sed reconhece o último argumento como um nome de arquivo.

  • sed não é muito adequado para correspondências em várias linhas. Veja por exemplo aqui .

O seguinte parece funcionar no seu exemplo:

sed -n "/<fmreq:name>object_name<\/fmreq:name>/ {n;p}" c3.xml | sed "s/^\s*<fmreq:value>\(.*\)<\/fmreq:value>//g"

Ou, com apenas uma invocação de sed :

sed -n "/<fmreq:name>object_name<\/fmreq\:name>/ {n;s/^\s*<fmreq:value>\(.*\)<\/fmreq:value>//g;p}" c3.xml

Repartição do que este comando faz:

  • A opção -n diz a sed para não imprimir o espaço padrão após terminar de processar a linha. Conseqüentemente, você precisa usar o comando p explicitamente para fazer isso.

  • /regex/ diz sed para executar os comandos que seguem apenas nas linhas que correspondem a regex .

  • O sed command n substitui o conteúdo do espaço de padrão pela próxima linha de entrada, que é a que contém o valor em que você está interessado.

  • O sed command s/regex/replacement/ substitui a primeira correspondência de regex no espaço padrão por replacement .

  • O comando sed p imprime a linha.

por 15.10.2017 / 10:57
0

Usando o XMLStarlet :

$ xml ed -u '//fmreq:property[fmreq:name="object_name"]/preceding-sibling::fmreq:property/fmreq:name' -v YYZ file.xml
<?xml version="1.0"?>
<fmreq:fileManagementRequestDetail xmlns:fmreq="http://foobar.com/filemanagement">
  <fmreq:property>
    <fmreq:name>YYC</fmreq:name>
    <fmreq:value>Memos</fmreq:value>
  </fmreq:property>
  <fmreq:property>
    <fmreq:name>object_name</fmreq:name>
    <fmreq:value>Correspondence</fmreq:value>
  </fmreq:property>
</fmreq:fileManagementRequestDetail>

A primeira parte do XPath, //fmreq:property[fmreq:name="object_name"] localizará o nó <fmreq:name>object_name</fmreq:name> , e o /preceding-sibling::fmreq:property/fmreq:name localizará o nó <fmreq:name> do nó <fmreq:property> anterior.

    
por 17.10.2017 / 11:52