Como adicionar tag para xml do arquivo existe usando o shell linux

1

xml1.xml

<app>
    <bbb>
        <jjj>test1</jjj>
     </bbb>
     <bbb>   
        <jjj>test2</jjj>
    </bbb>
</app>

xml2.xml

arquivo2 xml2.xml

<app>
    <bbb>   
       <jjj>test2</jjj>
    </bbb>
    <bbb>
        <jjj>test3</jjj>
    </bbb>
    <bbb>
        <jjj>test4</jjj>
    </bbb>
</app>

Posso combinar 2 arquivos para 1 arquivo como abaixo?

<app>
     <bbb>
        <jjj>test1</jjj>
     </bbb>
    <bbb>   
       <jjj>test2</jjj>
    </bbb>
    <bbb>
        <jjj>test3</jjj>
    </bbb>
    <bbb>
        <jjj>test4</jjj>
    </bbb>
</app>
    
por Thuc Vo 07.12.2015 / 16:51

3 respostas

1

Adaptado do link

$doc1 = new DOMDocument();
$doc1->load('xml1.xml');

$doc2 = new DOMDocument();
$doc2->load('xml2.xml');

// get 'app' element of document 1
$app1 = $doc1->getElementsByTagName('app')->item(0);

// iterate over 'bbb' elements of document 2
$items2 = $doc2->getElementsByTagName('bbb');
for ($i = 0; $i < $items2->length; $i ++) {
    $item2 = $items2->item($i);

    // import/copy item from document 2 to document 1
    $item1 = $doc1->importNode($item2, true);

    // append imported item to document 1 'app' element
    $app1 ->appendChild($item1);

}
$doc1->save('merged.xml');
    
por 07.12.2015 / 17:13
0

Parece que você pode fazer uma mesclagem sort e podá-lo. Basicamente sort apenas assume que você sabe o que está fazendo e executa uma única passagem em duas ou mais entradas, intercalando-as à medida que sua ordem de classificação lexicográfica converge.

Veja o que um -m erge sort do GNU imprime para o seu exemplo:

<app>
<app>
    <bbb>
    <bbb>
        <jjj>test1</jjj>
     </bbb>
     <bbb>
       <jjj>test2</jjj>
    </bbb>
    <bbb>
        <jjj>test2</jjj>
    </bbb>
</app>
        <jjj>test3</jjj>
    </bbb>
    <bbb>
        <jjj>test4</jjj>
    </bbb>
</app>

Então pelo menos está tudo dobrado agora, mas, como eu disse, você ainda tem que podá-lo. Este script sed fará isso pelos seus exemplos:

sort    -m      /tmp/xml[12]                    |
sed     -ne:n   -e'$!s|/a..> *$|bbb>|;$p'       \
                -e'\|^[^>]*b.*\n|{N;P;D;}'      \
-eN     -e's|\(.*\)\n\(.*\n\)* * *$||'      \
        -e's|\n|&|3;tD' -ebn -e:D -eP\;D

Ele apenas garante que ele tenha pelo menos três linhas empilhadas enquanto trabalha através da entrada e compara a primeira linha na pilha contra a última quando a primeira linha não é uma tag <bbb> .

<app>
    <bbb>
        <jjj>test1</jjj>
     </bbb>
     <bbb>   
       <jjj>test2</jjj>
    </bbb>
<bbb>
        <jjj>test3</jjj>
    </bbb>
    <bbb>
        <jjj>test4</jjj>
    </bbb>
</app>
    
por 08.12.2015 / 01:51
0

Você não pode usar o "shell" linux - para fazer XML, você realmente precisa de um analisador XML.

No entanto, existem muitas ferramentas de script que têm opções - o meu favorito é o perl e o biblioteca XML::Twig . (Isso é muito comumente disponível em gerenciadores de pacotes Unix, apesar de não fazer parte do 'core').

#!/usr/bin/env perl

use strict;
use warnings;

use XML::Twig;

#load both
my $first  = XML::Twig->new->parsefile('xml1.xml');
my $second = XML::Twig->new->parsefile('xml2.xml');

#iterate bbb elements in second file
foreach my $bbb ( $second->get_xpath('//bbb') ) {

    #extract 'text' of jjj element (of this bbb element)
    my $jjj = $bbb->first_child_text('jjj');

    #use xpath query to check it doesn't exist first.
    if ( not $first->get_xpath("//bbb/jjj[string()='$jjj']") ) {
        print $jjj, " not in first, splicing\n";

        #cut/paste (note -  done in memory, so original file isn't altered)
        $bbb->move( 'last_child', $first->root );
    }
}

#set output formatting - can do some odd things with particularly strange XMl.
$first->set_pretty_print('indented_a');
$first->print;

## if you want to save it:
open( my $output, '>', "combined.xml" ) or die $!;
print {$output} $first->sprint;
close($output);
    
por 08.12.2015 / 11:36