来自xml的php utf-8解码返回问号

Zee*_*ats 3 php xml encode decode special-characters

我在使用xml时遇到了一些问题.我知道这是一个简单的问题,但我找到的答案并没有解决我的问题.问题是,当我使用php domdocument将é或ä或其他特殊字符添加到我的xml文件时,它将é保存为xE9,将ä保存为xE4.我不知道这是否可以,但是当我想显示输出时,它会在这些地方显示问号.我试了很多.就像删除和添加php domdocument中de xml标头中的编码一样.我也尝试使用file_get_contents并使用php utf-8_decode来获取xml.我尝试使用iso intead,但没有解决我的问题.相反,我有时会得到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>
Run Code Online (Sandbox Code Playgroud)

和我的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);
}       
Run Code Online (Sandbox Code Playgroud)

这是添加新行功能

//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);
}
Run Code Online (Sandbox Code Playgroud)

一切正常,直到我添加特殊字符.这些都显示为问号.

hak*_*kre 5

好的以下现在有点粗糙/冗长,特别是你已经尝试过这么多.只是试着保持新鲜的眼睛,并考虑一旦你只做一点编码错误,它往往已经搞砸了.因此,正确理解哪些机制在这里起作用非常重要.

我尝试解决一些在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"?>
Run Code Online (Sandbox Code Playgroud)

这个非常简短的示例显示了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"?>
Run Code Online (Sandbox Code Playgroud)

如图所示,我们将用作第一个(版本)和第二个(编码)参数的内容将被写出.所以是的,我们可以做一些不允许的事情.但是这个XML声明允许什么?有一个XML版本AFAIK,即1.0.因此版本参数必须始终为1.0.编码允许什么?XML规范说明了所有IANA字符集,简而言之,它应该是这些常见字符集之一(应该而非必须):UTF-8,UTF-16,ISO-10646-UCS-2,ISO-10646-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"?>
Run Code Online (Sandbox Code Playgroud)

编码按预期工作,版本是装饰性的,但它显示:这是使用编码为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"?>
Run Code Online (Sandbox Code Playgroud)

因为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
Run Code Online (Sandbox Code Playgroud)

这不起作用.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"?>
Run Code Online (Sandbox Code Playgroud)

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

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

因此,让我们在您的问题中使用UTF-8文档中断此规则,并添加一些非UTF-8文本,例如在ISO-8859-1中.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>
Run Code Online (Sandbox Code Playgroud)

根据您查看输出的程序,它可能不会显示问号 而只显示"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>
Run Code Online (Sandbox Code Playgroud)

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