php-utf-8从xml解码返回问号


php utf-8 decode from xml returns question marks

我在使用xml时遇到了一些问题。我知道这是一个共同的问题,但我找到的答案并没有解决我的问题。问题是,当我使用php-domdocument将é或ä或另一个特殊字符添加到我的xml文件中时,它会将é保存为xE9,将ä保存为xE4。我不知道这是否可以,但当我想显示输出时,它会在这里显示问号。我试了很多。类似于在php-domdocument中删除和添加de-xml头中的编码。我还尝试使用file_get_contents和php utf-8_decode来获取xml。我试着使用iso intel,但没有解决我的问题。相反,我有时会遇到php-xml解析错误。我一定做错了什么,但怎么了?这是我的问题,也是我如何解决这个问题。我的xml文件如下所示:xE9和xE4具有黑色背景。

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <row id="1">
    <question>blah</question>
    <answer>blah</answer>
  </row>
  <row id="2">
    <question>xE9</question>
    <answer>xE4</answer>
  </row>
</root>

和我的php-xml类的一部分

function __construct($filePath) {
    $this->file = $filePath;
    $this->label = array('Vraag', 'Antwoord');
    $xmlStr = file_get_contents($filePath);
    $xmlStr = utf8_decode($xmlStr);
    $this->xmlDoc = new DOMDocument('1.0', 'UTF-8');
    $this->xmlDoc->preserveWhiteSpace = false;
    $this->xmlDoc->formatOutput = true;
    //$this->xmlDoc->load($filePath);   
    $this->xmlDoc->loadXML($xmlStr);
}       

这是添加新行功能

//creates new xml row and saves it in xml file
function addNewRow($question, $answer) {
    $nextAttr = $this->getNextRowId();
    $parentNode = $this->xmlDoc->documentElement;
    $rowNode = $this->xmlDoc->createElement('row');
    $rowNode = $parentNode->appendChild($rowNode);
    $rowNode->setAttribute('id', $nextAttr);    
    $q = $this->xmlDoc->createElement('question');
    $q = $rowNode->appendChild($q);
    $qText = $this->xmlDoc->createTextNode($question);
    $qText = $q->appendChild($qText);
    $a = $this->xmlDoc->createElement('answer');
    $a = $rowNode->appendChild($a);
    $aText = $this->xmlDoc->createTextNode($answer);
    $aText = $a->appendChild($aText);
    $this->xmlDoc->save($this->file);
}

在我添加特殊字符之前,一切都很好。这些都显示为问号。

好的,下面的内容现在有点粗糙/冗长,尤其是在您已经尝试了这么多的情况下。只要试着保持新鲜的眼光,并考虑到一旦你在编码方面只犯了一个小错误,它往往已经被搞砸了。因此,正确理解哪些力学在这里起作用是很重要的。

我试图解决在PHP的DOMDocument中运行的一些机制。你可能会觉得这很有趣或令人生畏,甚至可能最终解决方案非常简单,你甚至不需要更改你的PHP代码,但我无论如何都想解决这个问题,因为它在Stackoverflow和PHP手册中没有太多文档,有更多的参考资料是很好的,因为正确理解它很重要——正如我已经写的那样。

因此,默认情况下XML是UTF-8。UTF-8几乎是当今互联网的完美选择。当然,这在所有情况下都不是完全正确的,但总的来说,这是一个安全的选择。因此,XML本身和默认编码UTF-8是非常好的。

这对DOMDocument意味着什么?只是默认情况下DOMDocument将采用这种编码,我们不需要关心这一点。这是一个简单的展示,输出如下评论:

$doc = new DOMDocument();
$doc->save('php://output');
# <?xml version="1.0"?>

这个非常简短的示例显示了PHP对DOMDocument的默认UTF-8编码。该文档即使仍然不包含根节点,也已经通过在XML声明中不指定一个来显示默认的XML UTF-8编码<?xml version="1.0"?>

所以你可以说"但是我想要",当然你可以。这就是当您调用构造函数时,DOMDocument的编码参数的作用

$doc = new DOMDocument('1.0', 'UTF-8');
                               #####  Encoding Parameter
$doc->save('php://output');
# <?xml version="1.0" encoding="UTF-8"?>

如图所示,我们使用的第一个(版本(和第二个(编码(参数将被写出。所以,是的,我们可以做一些不被允许的事情。但是在这个XML声明中允许什么呢?有一个XML版本AFAIK,它是1.0。因此,版本参数必须始终为1.0。什么是允许的编码?XML规范规定了所有IANA字符集,简而言之,它应该是以下常见字符集之一(应该,而不是必须(:UTF-8、UTF-16、ISO-10646-UCS-2、ISO-10645-UCS-4、ISO-8859-1到ISO-8859-9、ISO-2022-JP、Shift_JIS、EUC-JP。好吧,哇,这已经是一个很长的清单了。

因此,让我们看看PHP的DOMDocument实际上允许我们做什么:

$doc = new DOMDocument('♥♥ love, hugs and kisses ♥♥', 'UTF-8');
$doc->save('php://output');
# <?xml version="♥♥ love, hugs and kisses ♥♥" encoding="UTF-8"?>

编码工作如预期,版本只是装饰性的,但它显示:这是使用编码为UTF-8的Unicode字符。现在让我们将编码更改为不同的内容:

$doc = new DOMDocument('♥♥ love, hugs and kisses ♥♥', 'ISO-8859-1');
$doc->save('php://output');
# <?xml version="&#9829;&#9829; love, hugs and kisses &#9829;&#9829;" encoding="ISO-8859-1"?>

因为Unicode红心在ISO-8859-1中没有位置,所以它们被替换为相应的数字HTML实体(&#9829;(。如果我们直接在其中添加一个ISO-8859-1字符,如ö(PHP中的二进制字符串"'xF6"(,会发生什么?

$doc = new DOMDocument("♥♥ l'xF6ve, hugs and kisses ♥♥", 'ISO-8859-1');
$doc->save('php://output');
# Warning: DOMDocument::save(): output conversion failed due to conv error, 
#          bytes 0xF6 0x76 0x65 0x2C
#                ^^^^  |    |    |
#                "ö"   v    e   space

这不起作用。DOMDocument告诉我们,我们提供的信息无法转换为ISO-8859-1输出。这是意料之中的:DOMDocument希望所有给定的输入都是UTF-8。所以这次让我们从unicode中取ö:

$doc = new DOMDocument('♥♥ löve, hugs and kisses ♥♥', 'ISO-8859-1');
$doc->save('php://output');
# <?xml version="&#9829;&#9829; l�ve, hugs and kisses &#9829;&#9829;" encoding="ISO-8859-1"?>

尽管钻石上有这个问号,但现在看起来很好。因为在我的计算机上,显示/输出是UTF-8,所以不能在这里显示ISO-8859-1ö字符。所以我的显示器用�Unicode字符"替换字符"(U+FFFD(。这是正确的,"ö"现在起作用了。

到目前为止,这清楚地表明,您只能将UTF-8编码的字符串传递到DOMDocument中,这与您为该文档指定的XML编码无关。

因此,让我们用UTF-8文档打破这个规则,如您的问题中所述,并添加一些非UTF-8文本,例如在ISO-8859-1 resp中。Windows-1252:

$doc = new DOMDocument('1.0', 'UTF-8');
$doc->appendChild($doc->createElement('root'))
    ->appendChild($doc->createElement('question'))
    ->appendChild($doc->createTextNode("l'xF6ve, hugs and kisses"));
$doc->save('php://output');
# <?xml version="1.0" encoding="UTF-8"?>
# <root><question>l�ve, hugs and kisses</question></root>

根据您查看输出的程序,它可能不会显示问号�但只是"xF6"。我想说你的文件编辑器就是这样。

因此,这也是解决方案:当您将字符串数据传递到DOMDocument时,请确保它是UTF-8编码的:

->appendChild($doc->createTextNode(utf8_encode("l'xF6ve, hugs and kisses")));
                                   ########### (works with ISO-8859-1 only (!))
# <?xml version="1.0" encoding="UTF-8"?>
# <root><question>löve, hugs and kisses</question></root>

或者在您的情况下,告诉浏览器您的网站需要UTF-8。然后你就不需要重新编码任何东西,因为你的浏览器已经用正确的编码发送了数据。W3C为我建议您现在阅读的主题收集了一些有用的资源:

  • 多语言表单编码