Embora XML seja um formato somente texto, tentar manipulá-lo com sed e / ou awk é uma idéia terrível, porque o formato tem tantos casos e exceções no modo em que é usado, que você deve realmente pensar nele. como um formato binário que só acontece de ser legível a olho nu, em vez de um formato de texto. Parece fácil, até você realmente tentar. A resposta curta é, apenas, não.
Em vez disso, sugiro o uso de uma linguagem de script que tenha uma biblioteca para lidar com XML. Existem muitas dessas bibliotecas. Em Perl, você poderia fazer algo ao longo destas linhas:
#!/usr/bin/perl -wCSDA
use strict;
use warnings;
package MyFilter;
use base qw(XML::SAX::Base);
sub new {
my $class = shift;
my @args = @_;
my $self = $class->SUPER::new(@args);
$self->{indesc} = 0;
return $self;
}
sub start_element {
my $self = shift;
my $data = shift;
if ($data->{LocalName} eq "description") {
$self->{indesc} = 1;
}
return $self->SUPER::start_element($data);
}
sub end_element {
my $self = shift;
my $data = shift;
if ($data->{LocalName} eq "description") {
$self->{indesc} = 1;
}
return $self->SUPER::end_element($data);
}
sub characters {
my $self = shift;
my $data = shift;
if(($self->{indesc}) == 1) {
$data->{Data} =~ s/\.[^\.]*<a href/.<a href/;
}
return $self->SUPER::characters($data);
}
package main;
use XML::SAX::ParserFactory;
use XML::SAX::Writer;
my $writer = XML::SAX::Writer->new();
my $filter = MyFilter->new(Handler => $writer);
my $input = XML::SAX::ParserFactory->parser(Handler => $filter);
$input->parse_uri("input.xml");
Isso funciona da seguinte maneira:
- A linha
package MyFilter;
sinaliza uma classe que implementa um filtro XML :: SAX:
-
sub new
é o construtor, que realmente cria apenas o $self->{indesc}
flag.
-
sub start_element
é chamado toda vez que um elemento XML é aberto. Verificamos se o elemento em questão é o elemento <description>
; se assim for, nós definimos o sinalizador (e passamos processamento adicional para a superclasse).
-
sub end_element
é chamado toda vez que um elemento XML é fechado. Verificamos se o elemento em questão é o elemento <description>
; se assim for, limparemos o sinalizador (e passaremos mais processamento para a superclasse).
-
sub characters
é chamado toda vez que um elemento de texto ou CDATA é processado. Nesse sub, nós verificamos se o sinalizador está configurado; se for, aplicamos uma expressão regular aos dados transmitidos para que qualquer sentença incompleta seja descartada (contando apenas de um ponto; a melhoria dessa regex é deixada como um exercício para o leitor ;-P)
- O pacote
main
contém o ponto inicial do script:
- Configura um
XML::SAX::Writer
(que simplesmente envia os dados XML analisados que são passados no formato XML novamente, para a saída padrão por padrão), conecta esse filtro ao nosso filtro (para que os dados XML passados ao gravador contenham os dados XML que o filtro recebeu com as sentenças incompletas removidas) e conecta o filtro a um analisador XML criado com XML::SAX::ParserFactory
.
- A cadeia inteira é então passada pela entrada (presume que ela pode ser encontrada em um arquivo chamado
input.xml
).
Se isso parece complicado, é porque é. Se você tiver uma escolha, diga não ao XML e use algo mais simples, como JSON ou YAML; -)