2009-11-09 11 views
5

Questo è un problema davvero strano. Mi ci è voluto praticamente tutto il giorno per ridurlo a un piccolo script eseguibile che dimostra pienamente il problema.Corruzione delle stringhe e caratteri non stampabili utilizzando XML :: Twig in Win32 Perl

Problema Sommario: sto usando XML::Twig per tirare un frammento di dati da un file XML, quindi sto attaccando i dati snippet nel bel mezzo di un altro pezzo di dati, chiamiamolo dati padre. All'inizio, i dati principali hanno questo strano carattere non stampabile all'inizio. Sono dati forniti dal fornitore, quindi non posso controllarlo. Il mio problema è che dopo aver inserito lo snippet di dati nel mezzo dei dati principali, il prodotto finale ha un nuovo carattere nuovo non stampabile all'inizio, oltre a quello avviato originariamente. Questo nuovo carattere non stampabile non si trovava né nei dati padre né nello snippet di dati figlio. Non so da dove viene, né come si inseriscono nei miei dati.

Sono dubbioso che si tratti di un errore XML :: Twig perché la corruzione della stringa si verifica durante la lettura di una riga da un filehandle in un ciclo while, ma non sono riuscito a ricreare il mio problema quando rimuovo l'XML: : Codice Twig nei miei script, quindi ho dovuto lasciarlo.

Questa è la mia prima esperienza con caratteri non stampabili nelle stringhe che sto tentando di elaborare. Devo fare qualcosa di speciale invece di trattarli come stringhe ordinarie o qualcosa del genere?

Utilizzo ActiveState Perl 5.10.1 e XML :: Twig 3.32 (più recente) e l'IDE Eclipse 3.5.1 su Windows XP.

Ecco uno script che illustra il problema:

use strict; 
use warnings; 
use XML::Twig; 

my $FALSE = 0; 
my $TRUE = 1; 
my $name = 'KurtsProgram'; 
my $task = 'MainTask'; 
my $hidden_char = "\xBF"; 
my $data = $hidden_char . 
'(********************************************* 
    Data-File-Header-Junk 
**********************************************) 

    PROGRAM MainProgram() 
    END_PROGRAM 

    TASK SecondaryTask() 
    END_TASK 

    TASK MainTask() 
     MainProgram; 
    END_TASK 
'; 
my $new_data = insertProgram($name, $task, $data); 

# test to see if results start out as expected 
if ($new_data =~ m/^\Q$hidden_char\E/) { 
    print "SUCCESS\n"; 
} 
else { 
    print STDERR "ERROR: What happened?\n"; 
    print STDERR "ORIGINAL: \n$data\n"; 
    print STDERR "MODIFIED: \n$new_data\n"; 
} 

sub insertProgram { 
    my ($local_name, $local_task, $local_data) = @_; 

    # get program section from XML template 
    my $twig = new XML::Twig; 
    $twig->parse('<?xml version="1.0"?> 
<TemplateSet> 
    <PROGRAM>PROGRAM <Name>ProgramNameGoesHere</Name>() 
    END_PROGRAM</PROGRAM> 
    <TASK>TASK <Name>TaskNameGoesHere</Name>() 
    END_TASK</TASK> 
</TemplateSet> 
'); 
    my $program = $twig->root->first_child('PROGRAM'); 

    # replace program name in XML template 
    $program->first_child('Name')->set_text($local_name); 
    my $insert = $program->text(); 

    # stick modified program into data 
    if ($local_data =~ s/(\s+PROGRAM\s+[^\s]+\s+\()/\n\n $insert $1/) { 
     # found it and inserted new program 
    } 
    else { 
     # not found 
     return; 
    } 

    # add program name to task list 
    my $added_program_to_task = $FALSE; 
    my $found_start = $FALSE; 
    my $found_end = $FALSE; 
    my $new_data = ""; 
    # open string as a filehandle for line by line processing 
    my $filehandle; 
    open($filehandle, '<', \$local_data) 
     or die("Can't open string as a filehandle: $!"); 
    while (defined (my $line = <$filehandle>)) { 
     # look for start of our task 
     if ( 
       (!$found_start) && 
       ($line =~ m/\s+TASK\s+\Q$local_task\E\s+\(/) 
      ) { 
      # found the task! 
      $found_start = $TRUE; 
     } 

     # look for end of our task 
     if (
       ($found_start) && (!$found_end) && 
       ($line =~ m/\s+END_TASK/) 
      ) 
     { 
      # found the end tag for the task section! 
      $found_end = $TRUE; 

      # add the program name to the bottom of the list 
      $line = "  " . $local_name . ";\n" . $line; 
      $added_program_to_task = $TRUE; 
     } 

     # compile new data from processed line or original line 
     $new_data = $new_data . $line; 
    } 
    close($filehandle); 

    if ($added_program_to_task) { 
     # success 
    } 
    else { 
     # unable to find task 
     return; 
    } 

    return $new_data; 
} 

Quando ho eseguito questo script, ottengo il seguente output:

ERROR: What happened? 
ORIGINAL: 
¿(********************************************* 
     Data-File-Header-Junk 
    **********************************************) 

     PROGRAM MainProgram() 
     END_PROGRAM 

     TASK SecondaryTask() 
     END_TASK 

     TASK MainTask() 
      MainProgram; 
     END_TASK 

MODIFIED: 
¿(********************************************* 
     Data-File-Header-Junk 
    **********************************************) 

     PROGRAM KurtsProgram() 
     END_PROGRAM 

     PROGRAM MainProgram() 
     END_PROGRAM 

     TASK SecondaryTask() 
     END_TASK 

     TASK MainTask() 
      MainProgram; 
      KurtsProgram; 
     END_TASK 

si può vedere il carattere aggiuntivo che è stato aggiunto alla davanti ai dati proprio sotto la M in MODIFICATO.

risposta

7

Ha eseguito una conversione di codifica da ISO-8859-1 a UTF-8 sul carattere: \xBF ->\xC2\xBF.

XML :: Twig converte tutti i dati in UTF-8 (see here).

Si potrebbe dire a Twig di mantenere la codifica di input utilizzando l'opzione keep_encoding (vedere anche le domande frequenti su XML :: Twig: My XML documents/data are produced by tools that do not grok Unicode, will XML::Twig help me there?).

Ma forse sarebbe meglio mantenere l'UTF-8, o magari abbandonare silenziosamente il personaggio, a seconda di cosa esattamente si andrà a fare con esso.

+0

I dati tornano direttamente all'applicazione di un fornitore, quindi il carattere speciale non stampabile nella parte anteriore dei dati deve rimanere esattamente come originariamente. –

+0

In questo caso 'keep_encoding' dovrebbe fare il lavoro. – mercator

1

Non riesco a dare un senso al tuo codice, è ancora troppo complesso per essere rapidamente sottoposto a debug, ma forse il problema ha a che fare con un BOM (vedi lo Unicode BOM FAQ) che verrebbe ignorato all'inizio di un XML documento, ma non se lo copi nel mezzo di un altro? semplicemente indovinando qui a causa del valore xBF, fa parte della distinta base di un documento UTF-8.

Problemi correlati