【问题标题】:Getting encoding error when using hash keys to write xml files with XML::LibXML使用哈希键编写带有 XML::LibXML 的 xml 文件时出现编码错误
【发布时间】:2012-01-16 15:35:09
【问题描述】:

这个问题与这个问题有关:Hash keys encoding: Why do I get here with Devel::Peek::Dump two different results?
当我取消注释 # utf8::upgrade( $name ); 行或注释掉 $hash{'müller'} = 'magenta'; 行时,它可以工作。

#!/usr/bin/env perl
use warnings;
use 5.014;
use utf8;
binmode STDOUT, ':encoding(utf-8)';
use XML::LibXML;

# Hash read in from a file:
# ... 
my %hash = ( 'müller' => 'green', 'schneider' => 'blue', 'bäcker' => 'red' );
# ...

# change or add something
$hash{'müller'} = 'magenta';

# writing Hash to xml file
my $doc = XML::LibXML::Document->new('1.0', 'UTF-8' );
my $root = $doc->createElement( 'my_test' );

for my $name ( keys %hash ) {
    # utf8::upgrade( $name );
    my $tag = $doc->createElement( 'item' );
    $tag->setAttribute( 'name' => $name );
    my $tag_color = $doc->createElement( 'color' );
    $tag_color->appendTextNode( $hash{$name} );
    $tag->appendChild( $tag_color );
    $root->appendChild( $tag );
}
$doc->setDocumentElement($root);
say $doc->serialize( 1 );
$doc->toFile( 'my_test.xml', 1 );

输出:

error : string is not in UTF-8  
encoding error : output conversion failed due to conv error, bytes 0xFC 0x6C 0x6C 0x65  
I/O error : encoder error  
<?xml version="1.0" encoding="ISO-8859-1"?>  
<my_test>  
  <item name="m    
i18n error : output conversion failed due to conv error, bytes 0xFC 0x6C 0x6C 0x65
I/O error : encoder error

【问题讨论】:

    标签: xml perl unicode encoding hash


    【解决方案1】:

    根据 XML::LibXML,'müller' eq 'müller' 是真还是假取决于字符串在内部是如何存储的。那是一个错误。具体来说,为 UTF8 标志分配含义被称为“Unicode 错误”,并且在 this page 的“编码支持”部分中记录了 XML::LibXML 正是为了做到这一点。

    错误是known,但出于向后兼容性的原因,无法彻底修复。 Perl 提供了两个工具来解决 The Unicode Bug 的实例:

    utf8::upgrade( $sv );    # Switch to the UTF8=1 storage format
    utf8::downgrade( $sv );  # Switch to the UTF8=0 storage format
    

    前者是在这里使用的合适工具。

    sub _up { my ($s) = @_; utf8::ugprade($s); $s }
    $tag_color->appendTextNode( _up $hash{$name} );
    

    注意:即使不使用use utf8;,也可以使用utf8::upgrade。如果您的源代码是 UTF-8,请仅使用 use utf8;

    【讨论】:

    • 这是正确的答案,不幸的是,许多开发人员发现 Perl 的 Unicode 实现难以理解或令人困惑(考虑到早期的文档和当前的一部分,我不怪他们,考虑到 Encode 仍然暴露不相关的内部存储)。
    • @chansen,我认为造成混乱的最大因素是 Perl 本身在许多地方都存在 Unicode 错误。第二大是 UTF8 标志实际上是一个非常好的指示字符串中数据类型的指标,即使这不是它的意思。
    【解决方案2】:

    如果我将您的脚本保存为 iso-8859-1,则会收到错误消息。如果我将它保存为 utf-8,它可以工作。

    【讨论】:

    • 当我将源代码保存为 UTF-8 时,我得到了 OP 得到的结果。如果我将源保存为 iso-8859-1(并删除 use utf8;),除了相同的消息之外,我还会收到一个额外的“error : string is not in UTF-8”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-04
    • 1970-01-01
    • 2019-11-27
    相关资源
    最近更新 更多