O processamento de XML como texto geralmente não é uma solução robusta, mas se você insistir em fazê-lo, talvez possa usar o espaço de armazenamento do sed , por exemplo
sed -e '/<id>[0-9]*<\/id>/h' -e '/<root>/{x;p;x;}' file.xml
Eu tenho um arquivo XML que se parece com isso:
<id>456</id>
<root>
<value>1</value>
<intNum>2</intNum>
</root>
<root>
<eulav>1</eulav>
<muNtni>2</muNtni>
</root>
Eu quero lembrar de <id>456</id>
e fazer isso:
sed 's/\<root\>/\
\<root\>
$herecomestheid
Basicamente, o que isto faz é substituir <root>
por <root>\n<id>456</id>
. \n
neste caso significa nova linha. Eu já sei disso, mas o problema que estou tendo é lembrar <id>456</id>
e mantê-lo pronto para uso posterior.
Eu tentei isso (o que obviamente não funcionou):
sed -i '' 's/\<root\>/\
\<root\>\
\<id\>.\<\/id\>/g'
e eu tentei fazer algo assim:
cat file.xml | grep '\<id\>*\<\/id\>'
E tentei transformar a saída grep em uma variável. E isso obviamente não funcionou também.
EDIT: <id>*</id>
está supostamente na raiz.
sed -e :b -e '$!{N;\|<id>.*\n<root>|!bb
};do what ever you want to do with all of those lines now....'
Concordo com a steeldriver que h
oldspace é provavelmente a melhor aposta, mas há outras opções. Às vezes, não podemos nos incomodar em gerenciar os dois buffers - ou, como geralmente é problema meu - já estamos gerenciando os dois buffers. O trecho acima empilha linhas no espaço padrão. Contanto que sempre ocorra entre <id>
tags, ele preencherá recursivamente o espaço padrão com o bloco de dados desejado antes de prosseguir para a linha 2 - isto é, ele fará isso enquanto os buffers não implodem enquanto isso - mas isso é algo difícil de fazer hoje em dia .
Além disso, voltando à parte do h
old space, e x
change realmente troca h
old e space space. Usá-lo uma vez renderiza o buffer padrão como o buffer h
old e vice-versa. Este efeito sobrevive aos ciclos de linha. Muitas vezes, o que eu faço é ler um arquivo até chegar a uma linha inicial, realizar edições preliminares, depois trocar e manter H
olding até obter outra. Quando meu script troca de volta, acaba em um bloco atrás - no último marcador que eu liguei, além de tudo, H
eld enquanto isso. É uma maneira simples de armazenar apenas o máximo que for necessário.
E assim, outra maneira de implementar um loop como você deseja fazer é:
sed -e '/<id>/h;//!H;/<root>/!{$!d' -e '};x...'
A partir desse ponto, seu espaço de padrão é H
old space e vice-versa. h
old irá sobrescrever h
espaço antigo com o espaço padrão atual sempre que for usado - então o exemplo acima inicia um novo buffer com uma linha <id>
todas as vezes. !H
acrescenta todas as linhas intermediárias a H
old space, cada uma seguindo um caractere \n
ewline. $!d
elimina o espaço padrão em cada linha que é !
, não a $
última, quando a linha atual estiver com segurança H
eld e inicia o próximo ciclo de linha e, portanto, a alteração x
ocorre apenas em <root>
corresponde ao momento em que o bloco inteiro está esperando por você.
Lembre-se apenas que, no seu bloco último , o marcador é provavelmente a última linha, caso seja diferente das correspondências <root>
.
Mas ...
De acordo com sua edição, não vejo nenhum motivo pelo qual você não possa se safar:
sed '/<id>/h;//d;\|</root>|G
' <<\INPUT
unimportant 1
<id> number 1 </id>
<root> sub text
more text
more text
</root>
<root> sub text as well
and more text
and more text
</root>
unimportant 2
<id> number 2 </id>
<root> sub text
more text
more text
</root>
<root> sub text
and more text
and more text
</root>
INPUT
Há <id>
linhas são h
eld (novamente: sobrescrevendo h
espaço antigo) e, em seguida, d
da saída. Quando ocorre uma coincidência </root>
, sed
G
define o espaço h
old anexado ao espaço padrão antes de imprimir automaticamente os resultados no final do ciclo de linha, que se parece com:
unimportant 1
<root> sub text
more text
more text
</root>
<id> number 1 </id>
<root> sub text as well
and more text
and more text
</root>
<id> number 1 </id>
unimportant 2
<root> sub text
more text
more text
</root>
<id> number 2 </id>
<root> sub text
and more text
and more text
</root>
<id> number 2 </id>
Uma solução usando awk
seria
awk '/<id>/{id=$0}/<root>/{print id}1' file.xml
Se você não quiser imprimir a linha <id>
, pule essa linha adicionando next
.
awk '/<id>/{id=$0;next}/<root>/{print id}1' file.xml
Tags bash grep text-processing sed