filtra o arquivo xml de texto

2

Eu tenho um grande (com alguns milhares de registros) arquivo XML do qual eu gostaria de filtrar apenas campos específicos. exemplo da construção do arquivo:

<A>
<id>123</id>
<B>
   <C>value1</C>
   <D>value2</D>
   ....
   <E></E>
</B>
<Z></Z>
...
<Y></Y>
<A>

Gostaria de filtrar esse arquivo XML e conter apenas o id e os dados contidos nos campos C e D.

Como isso pode ser feito?

    
por user1977050 24.08.2015 / 10:34

3 respostas

4

A ferramenta xmlstarlet fará isso:

xmlstarlet sel -t -m /A -o ID, -v id -n -o C, -v //C -n -o D, -v //D -n test.xml 

Para cada A sob o elemento raiz ( -m /A ), imprime a string "ID" ( -o ID, ), o conteúdo do id ( -v id ), uma nova linha ( -n ) e da mesma forma para as crianças C ( -v //C ) e D ( -v //D ) com seus respectivos cabeçalhos. As barras duplas são o XPath para "qualquer lugar abaixo do nó correspondente".

O resultado, conforme testado no meu sistema, usando seu arquivo de teste, é a saída separada por vírgula:

ID,123
C,value1
D,value2

Se você não quiser os cabeçalhos, omita os argumentos -o <whatever> .

Agradecemos a este artigo para obter explicações.

    
por 24.08.2015 / 11:50
0

Para responder a essa pergunta corretamente, seria ideal que precisássemos de um exemplo melhor - um xml válido é um bom começo.

Além disso - um exemplo de saída desejada. Você não indica, por exemplo, onde deseja que os elementos <C> e <D> terminem em seu XML resultante. Eles são filhos de <B> - você deseja preservar B ou reparent C e D na raiz?

No entanto, reconstruir genericamente XML é bastante fácil usando XML::Twig e perl .

Por exemplo Assim:

#!/usr/bin/perl

use strict;
use warnings;

use XML::Twig;

my @wanted = qw ( C D id );


my %wanted = map { $_ => 1 } @wanted; 

sub delete_unwanted_tags {
   my ( $twig, $element ) = @_;
   my $tag = $element -> tag;
   if ( not $wanted{$tag} ) {
        $element -> delete;
   }
}

my $twig = XML::Twig -> new ( twig_handlers => { _all_ => \&delete_unwanted_tags } );
$twig -> parse ( \*DATA );
$twig -> print;

__DATA__
<A>
<id>123</id>
<B>
   <C>value1</C>
   <D>value2</D>
   <E></E>
</B>
<Z></Z>
<Y></Y>
</A>

Como ainda não dissemos "keep <B> ", o resultado é:

<A>
  <id>123</id>
</A>

Adicionando <B> à lista wanted :

<A>
  <id>123</id>
  <B>
    <C>value1</C>
    <D>value2</D>
  </B>
</A>

Se, no entanto, o que você deseja fazer é reparent C e D into A :

#!/usr/bin/perl

use strict;
use warnings;

use XML::Twig;

my @wanted   = qw ( id);
my @reparent = qw ( C D );

#turn the above into hashes, so we can do "if $wanted{$tag}"
my %wanted   = map { $_ => 1 } @wanted;
my %reparent = map { $_ => 1 } @reparent;

sub delete_unwanted_tags {
    my ( $twig, $element ) = @_;
    my $tag = $element->tag;
    if ( not $wanted{$tag} ) {
        $element->delete;
    }
    if ( $reparent{$tag} ) {
        $element->move( 'last_child', $twig->root );
    }
}

my $twig = XML::Twig->new(
    pretty_print  => 'indented_a',
    twig_handlers => { _all_ => \&delete_unwanted_tags }
);
$twig->parse( \*DATA );
$twig->print;

__DATA__
<A>
<id>123</id>
<B>
   <C>value1</C>
   <D>value2</D>
   <E></E>
</B>
<Z></Z>
<Y></Y>
</A>

Observação - o "manipulador de ramificação" é chamado no fim de cada elemento (quando uma tag de fechamento é encontrada) e é por isso que funciona - recursamos para encontrar C e D antes de terminarmos o processamento (e a exclusão) B .

Isso produz:

<A>
  <id>123</id>
  <C>value1</C>
  <D>value2</D>
</A>

Acima, usei __DATA__ , \*DATA e parse porque permite ilustrar o XML e as técnicas. Você provavelmente deve usar em vez de parsefile('my_file.xml') em vez de parse(\*DATA) .

    
por 28.08.2015 / 15:04
0

Use o lxgrep no kit de ferramentas ltXML2 (Edinburgh University), por exemplo

$ lxgrep -w A '(id|C|D)' test.xml
<A>
<id>123</id>
<C>value1</C>
<D>value2</D>
</A>

Usar esse tipo de ferramenta é muito mais rápido e mais confiável do que usar a sua própria ferramenta.

Perguntas frequentes sobre XML: link

    
por 12.07.2016 / 00:26

Tags