Sed / awk Regex: XML feed

0

Estou pesquisando um REGEX específico, três dias tentando e tentando não encontrar a resposta certa.

Eu preciso excluir partes específicas de um feed xml, tentei com sed, awk e não está funcionando direito.

O que eu tenho:

...Something before
<description><![CDATA[Des  chercheurs de l&#x27;université de Columbia à New York ont mis au point un nouveau moyen de cacher un message dans un texte sans en altérer le sens et sans dépendre d&#x27;un format de fichier particulier. Nommée FontCode, cette idée est <a href="https://korben.info/cacher-des-informations-dans-un-texte-grace-a-des-modifications-sur-les-caracteres.html">Passage a la news suivante</a>]]></description>
... Other news

O que eu preciso:

...Something before
<description><![CDATA[Des  chercheurs de l&#x27;université de Columbia à New York ont mis au point un nouveau moyen de cacher un message dans un texte sans en altérer le sens et sans dépendre d&#x27;un format de fichier particulier.<a href="https://korben.info/cacher-des-informations-dans-un-texte-grace-a-des-modifications-sur-les-caracteres.html">Passage a la news suivante</a>]]></description>
... Other news
  • Selecione as várias instâncias entre "< \ description > < / description >
  • Remove a última sentença que não está completa (antes de href, "Nommée FontCode, cette idée est")

Obrigado por ajudar! ;)

    
por w4rell 09.04.2018 / 15:02

3 respostas

0
sed -E '/^[[:blank:]]*<description><!\[CDATA\[/s/([!?.])[^!?.<]*<a/ <a/' file

Isso procurará todas as linhas que começam com a string exata <description><![CDATA[ (possivelmente precedida por espaços ou tabulações). Nessas linhas, uma substituição será executada.

A substituição corresponde a um terminador de sentença ( [!?.] ) seguido por qualquer número de caracteres que não sejam terminadores de frase ou < e a string <a . Isso será substituído pelo terminador da primeira frase, um espaço e a string <a .

    
por 09.04.2018 / 15:51
0

Eu testei pelo comando abaixo sed e funcionou bem para mim

 sed "s/particulier\..*<a/particulier.<a/g" file

saída

...Something before
<description><![CDATA[Des  chercheurs de l&#x27;université de Columbia à New York ont mis au point un nouveau moyen de cacher un message dans un texte sans en altérer le sens et sans dépendre d&#x27;un format de fichier particulier.<a href="https://korben.info/cacher-des-informations-dans-un-texte-grace-a-des-modifications-sur-les-caracteres.html">Passage a la news suivante</a>]]></description>
... Other news
    
por 09.04.2018 / 16:04
0

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; -)

    
por 09.04.2018 / 16:20