Win32 Perl で XML::Twig を使用すると文字列の破損と印刷不可能な文字が発生する
-
19-09-2019 - |
質問
これは本当に奇妙な問題です。問題を完全に示す小さな実行可能なスクリプトにまで絞り込むのに、ほぼ一日かかりました。
問題の概要: 使っています XML::Twig XML ファイルからデータ スニペットを取得するには、そのデータ スニペットを別のデータ (親データと呼びます) の中央に貼り付けます。親データを開始すると、先頭にこの奇妙な印刷不可能な文字が含まれています。ベンダー提供のデータなので、私が制御することはできません。私の問題は、データスニペットを親データの中央に貼り付けた後、最終製品には 新しい 元の文字に加えて、その先頭に印刷不可能な文字が追加されます。この新しい印刷不可能な文字は、親データにも子データ スニペットにもありませんでした。それがどこから来ているのか、どのようにしてデータに侵入しているのかわかりません。
while ループでファイルハンドルから行を読み取るときに文字列の破損が発生するため、これが XML::Twig のバグであるとは思えませんが、XML::Twig コードを削除しても問題を再現できませんでした。私のスクリプトなので、それを残しておかなければなりませんでした。
処理しようとしている文字列に印刷不可能な文字が含まれるのはこれが初めての経験です。通常の文字列などとして扱うのではなく、何か特別なことをする必要があるのでしょうか?
Windows XP 上で ActiveState Perl 5.10.1、XML::Twig 3.32 (最新)、および Eclipse 3.5.1 IDE を使用しています。
この問題を示すスクリプトは次のとおりです。
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
MODIFIED の M のすぐ下に、データの先頭に追加された余分な文字が表示されます。
解決
これは、文字のUTF-8エンコーディングへの変換ISO-8859-1を行っている:。\xBF
- > \xC2\xBF
XML ::小枝はUTF-8に、そのすべての入力を変換します(こちらをご覧ください。)。
あなたは<のhref =「http://search.cpan.org/~mirod/XML-Twig-3.32/Twig.pm#Encoding」のrel =「nofollowをnoreferrer」を使用してエンコード入力を維持するために小枝を言うことができますマイ:> keep_encoding
のオプションは、(また、XML ::小枝のFAQを参照してくださいXML文書は/データはUnicodeを完全に理解していないツールによって生成され、XMLます::小枝が私を助けて?に)。
しかし、おそらくあなたがそれをやろうとしている正確に何に応じて、UTF-8に保つ、あるいはおそらく静かに文字をドロップする方が良いでしょう。
他のヒント
コードの意味がよくわかりません。まだ複雑すぎてすぐにデバッグできませんが、問題は BOM に関係している可能性があります ( Unicode BOM FAQ)XML ドキュメントの先頭では無視されますが、別のドキュメントの途中にコピーした場合は無視されますか?ここでは xBF 値から推測していますが、これは UTF-8 ドキュメントの BOM の一部です。