2012-02-20 13 views
1

我想用SOAP :: Lite在复杂数据结构中传输UTF-8字符串。但事实证明,SOAP::Lite quietly converts all UTF-8 strings into base-64-encoded octets。问题在于反序列化does not revert the conversion,而且只有a straight base64 decode如何说服SOAP :: Lite在UTF-8响应中返回UTF-8数据?

这让我很困惑,用户应该如何确保他们从SOAP :: Lite响应中获得UTF-8数据。行走树并在所有字符串上运行decode_utf8看起来很浪费。

有什么建议吗?

编辑:简而言之,我如何让this test通过没有猴子补丁?

+0

您是否考虑过XML :: Compile?这是一段复杂的代码,但作者对于正确的支持一丝不苟。从我认识的那些使用过它的人那里,一旦你发现了这个东西,它会更好。我自己没有经验。 – 2012-02-21 01:25:26

+0

上次我看着它,我无法理解如何使用它在第一个地方。我认为我缺乏必需的领域知识(写作XSD和其他)。 – Mithaldu 2012-02-22 11:19:49

回答

0

使用is_utf8(278行)是邪恶的错误。由于我们不能相信编码字符数据的SOAP :: Lite正确(公平地说,这个代码很可能是在社区中如何处理这种特定类型的字符串处理之前编写的),所以我们只给它八位字节数据因此必须处理我们自己的编码/解码。选择一种编码,在将数据传递到S :: L之前应用它,在接收数据后将其反转。

use utf8; 
use strictures; 
use Encode qw(decode encode); 
use SOAP::Lite qw(); 
use Test::More; 

my $original = 'mü'; 
my $xml  = SOAP::Serializer->envelope(
    freeform => encode('UTF-8', $original, Encode::FB_CROAK | Encode::LEAVE_SRC) 
); 
my ($roundtrip) = map { 
    decode('UTF-8', $_, Encode::FB_CROAK | Encode::LEAVE_SRC) 
} values %{SOAP::Deserializer->deserialize($xml)->body}; 

is(length($original), length($roundtrip), 
    'Perl character string round-trips without changing length'); 
done_testing; 
+0

请注意我如何说“复杂的数据结构”。为了尽量减少理解工作量,这个测试是最小的,但请想象它是一个四维散列,可以倾倒到20kbyte左右。 :) – Mithaldu 2012-02-20 22:18:26

+1

然后编码为JSON,而不是UTF-8。 – daxim 2012-02-20 22:30:42

+0

我可以漂浮它。我不能完全控制SOAP服务器,但我认为他会接受建议。感谢这个想法。 – Mithaldu 2012-02-20 22:36:39

1

我刚碰到同样的问题,发现上面的讨论很有用。正如你在OP中所说的那样,问题在于数据是用base64编码的,而is_utf8标志会丢失。 serlializer会发生什么情况,将任何非ascii字符的字符串视为二进制文件。我通过调整序列化器来完成我想要的操作。这可能有奇怪的后果,但它在我的处境工程..

use strictures; 
use Test::More; 
use SOAP::Lite; 
use utf8; 
use Data::Dumper; 

my $data = "mü\x{2013}"; 
my $ser = SOAP::Serializer->new; 
$ser->typelookup->{trick_into_ignoring} = [9, \&utf8::is_utf8 ,'as_utf8_string']; 
my $xml = $ser->envelope(freeform => $data); 
my ($cycled) = values %{ SOAP::Deserializer->deserialize($xml)->body }; 

is(length($data), length($cycled), "UTF-8 string is the same after serializing"); 
done_testing; 

sub check_utf8 { 
    my ($val) = @_; 
    return utf8::is_utf8($val); 
} 


package SOAP::Serializer; 
sub as_utf8_string { 
    my $self = shift; 
    my($value, $name, $type, $attr) = @_; 
    return $self->as_string($value, $name, $type, $attr); 
} 
1; 

的9意味着UTF8检查,在检查非ASCII字符之前进行。如果utf8标志处于打开状态,则将其视为“普通”字符串。