我写了一个脚本,它将哈希转换为XML,并从XML::LibXML::Document
返回toString
函数的结果。我似乎不可能打印结果(字符串)而不会破坏XML文档中的UTF-8字符。
我尝试将binmode
用于STDOUT,并使用/避免setEncoding
用于XML文档。两者都没有像我预期的那样奏效。
唯一的解决方案"为此,在将字符串返回到要打印它的脚本之前,使用$XML::LibXML::skipXMLDeclaration = 1;
或decode
字符串禁用XML声明。
我只是没有得到这个声明行的部分。我甚至可以将字符串(带有此声明行)返回到我的第二个脚本,将其写入文件而没有任何残缺的字符,如果我直接打印到STDOUT,则会出现残缺的字符。如上所述,我甚至尝试使用binmode
。
那么,toString
或者将XML打印到STDOUT一般有什么问题?我错过了什么吗?如果需要,我当然可以提供一些代码。
在这个特定情况下,我刚刚从XML::Simple
切换到XML::LibXML
,它与XML::Simple
一起运行良好。我知道XML::Simple
不是那么好;我只是好奇为什么它工作正常,XML::LibXML
让我整天忙碌。
这是我使用的代码示例。说实话,这个片段就像一个魅力,我仍然在努力寻找与我的真实剧本不同的东西,我显然无法在这里发布。但为了告诉你我在做什么这可能没问题:
create_xml.pm
#!/usr/bin/perl
package create_xml;
use XML::LibXML;
use utf8;
sub convertHash
{
my ($hash) = @_;
my $xmlDoc = XML::LibXML::Document->new();
$xmlDoc->setEncoding('UTF-8');
my $xmlRoot = $xmlDoc->createElement('TestXML');
foreach my $key (keys %$hash)
{
my $wert = $hash->{$key};
my $element = $xmlDoc->createElement($key);
$element->appendTextNode($wert);
$xmlRoot->appendChild($element);
}
my $wsStatusElement = $xmlDoc->createElement('FixedElement');
$wsStatusElement->appendTextNode(123);
$xmlRoot->appendChild($wsStatusElement);
$xmlDoc->setDocumentElement($xmlRoot);
open(XML, '>', 'test1.xml');
print XML $xmlDoc->toString(1);
close(XML);
return $xmlDoc->toString(1);
}
1;
print_xml.pl
#!/usr/bin/perl
use lib '.';
use create_xml;
use utf8;
my %testhash;
$testhash->{'A'} = 15;
$testhash->{'B'} = 'abc';
$testhash->{'C'} = 'äöüä';
$testhash->{'D'} = '€';
my $xml = create_xml::convertHash($testhash);
open(XML, '>', 'test2.xml');
print XML $xml;
close(XML);
print $xml;
使用这个脚本,两个写入的xml文件都可以,但最后一次打印的输出被破坏了。我的€看起来像<D>â�¬</D>
。如前所述,此代码段正常工作。在我发现差异之后,我稍后会编辑我的问题。
我终于找到了问题所在。我使用了一个名为use open ':std', ':encoding(UTF-8)';
的perlmodule。那么为什么这会破坏我的字符进行打印,而不是写入文件呢?我仍然很困惑,觉得我错过了什么。这是已经utf8编码的字符被编码两次的部分吗?是否可以重置此选项?
答案 0 :(得分:3)
$doc->toString
返回已编码的字符串。使用的编码是由$doc->setEncoding
设置并由$doc->actualEncoding
返回的编码。默认情况下,这是新文档的UTF-8,或现有文档的原始编码。
因此,您需要做的就是将$doc->toString
的输出打印到STDOUT,而无需先向STDOUT添加编码层。
$ perl -e'
use strict;
use warnings;
use XML::LibXML qw( );
my $doc = XML::LibXML::Document->new(1.0, "UTF-8");
my $root = $doc->createElement("root");
$root->appendText("\x{2660}");
$doc->setDocumentElement($root);
print $doc->toString();
' | od -c
0000000 < ? x m l v e r s i o n = " 1
0000020 " e n c o d i n g = " U T F -
0000040 8 " ? > \n < r o o t > 342 231 240 < /
0000060 r o o t > \n
0000066
很难说你遇到了什么问题,因为你没有提供问题的演示。
最可能的问题是,当您传递解码文本时,您将编码文本传递给XML :: LibXML。
另一个不太可能的可能性是你与appendText
发生冲突, sub _u($) { my $s = shift; utf8::upgrade($s); $s }
$root->appendText("\x{C9}ric"); # Buggy
$root->appendText(_u("\x{C9}ric")); # Ok
和其他向文档添加文本的方法受到影响。您可以通过“升级”文本来解决该错误。
K1 - V1
K1 - V2
K1 -V3
K2 - V4
K2- V5
K2-V6
答案 1 :(得分:2)
它对我有用。
$ perl -Mutf8 -MXML::LibXML -we '
my $xml =q{<?xml version="1.1" encoding="utf-8"?><r>ěščřž</r>};
my $doc = XML::LibXML->load_xml(string => $xml);
binmode STDOUT, "encoding(UTF-8)";
print $doc->findvalue("r"), "\n";
'
ěščřž
使用toString
,您需要使用Encode的decode
:
print decode("utf-8", $doc->toString), "\n";