Повреждение строки и непечатаемые символы с использованием XML :: Twig в Win32 Perl - PullRequest
5 голосов
/ 10 ноября 2009

Это действительно странная проблема. Практически весь день у меня ушло на то, чтобы свести его к маленькому исполняемому скрипту, который полностью демонстрирует проблему.

Краткое описание проблемы: Я использую XML :: Twig , чтобы извлечь фрагмент данных из файла XML, а затем вставляю этот фрагмент данных в середину другого фрагмента. данных, давайте назовем это родительские данные. Родительские данные имеют этот странный непечатный символ в начале, когда я начинаю. Это данные, предоставленные поставщиком, поэтому я не могу их контролировать. Моя проблема в том, что после того, как я вставил фрагмент данных в середину родительских данных, конечный продукт имеет в своем начале новый непечатаемый символ в дополнение к тому, с которого он изначально был создан. Этот новый непечатаемый символ не был ни в родительских данных, ни во фрагменте дочерних данных. Я не знаю, откуда это происходит, и как это попадает в мои данные.

Я сомневаюсь, что это ошибка XML :: Twig, потому что происходит повреждение строки при чтении строки из дескриптора файла в цикле while, но мне не удалось воссоздать мою проблему при удалении XML :: Код ветки в моих сценариях, поэтому мне пришлось оставить его внутри.

Это мой первый опыт работы с непечатными символами в строках, которые я пытаюсь обработать. Нужно ли делать что-то особенное вместо того, чтобы относиться к ним как к обычным строкам или к чему-то еще?

Я использую ActiveState Perl 5.10.1 и XML :: Twig 3.32 (последняя версия) и Eclipse 3.5.1 IDE в Windows XP.

Вот скрипт, который демонстрирует проблему:

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

Когда я запускаю этот скрипт, я получаю следующий вывод:

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

Вы можете увидеть дополнительный символ, который был добавлен в начало данных прямо под буквой M. в ИЗМЕНЕНО.

Ответы [ 2 ]

7 голосов
/ 10 ноября 2009

Выполнено преобразование кодировки ISO-8859-1 в UTF-8 для символа: \xBF -> \xC2\xBF.

XML :: Twig преобразует весь свой ввод в UTF-8 ( см. Здесь ).

Вы можете указать Twig сохранить кодировку ввода, используя опцию keep_encoding (см. Также FAQ по XML :: Twig: Мои XML-документы / данные создаются инструментами, которые не работают Unicode, поможет ли мне там XML :: Twig? ).

Но, возможно, было бы лучше оставить UTF-8 или, возможно, молча отбросить персонажа, в зависимости от того, что именно вы собираетесь с ним делать.

1 голос
/ 10 ноября 2009

Я не могу понять ваш код, он все еще слишком сложен, чтобы его можно было быстро отладить, но, возможно, проблема связана с спецификацией (см. FAQ по Unicode ), которая будет игнорируется в начале XML-документа, но нет, если вы копируете его в середине другого документа? просто догадываюсь здесь из-за значения xBF, это часть спецификации для документа UTF-8.

...