如何使用XML :: LibXML

时间:2016-06-09 13:28:57

标签: xml perl utf-8 libxml2

我写了一个脚本,它将哈希转换为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编码的字符被编码两次的部分吗?是否可以重置此选项?

2 个答案:

答案 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,您需要使用Encodedecode

print decode("utf-8", $doc->toString), "\n";