【问题标题】:php utf-8 decode from xml returns question marks来自xml的php utf-8解码返回问号
【发布时间】:2013-04-24 20:43:07
【问题描述】:

我在使用 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>

和我的 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);
}

在我添加特殊字符之前一切正常。这些显示为问号。

【问题讨论】:

  • 您引用了特殊字符,但您的 XML 示例没有任何字符。 它将é保存为xE9,将ä保存为xFC是什么意思。您的 PHP 代码只是显示您将 XML 加载到 DOMDocument 对象中。
  • xml例子只是xml结构的一个例子。正如我在上面解释的那样,如果我将 é 和 ä 添加到文件中,它会将 xE9 和 xFC 保存到 xml 文件中。这是通过我的类中带有 php 函数的 html 输入字段完成的。
  • 没有真实的例子你希望如何获得帮助?
  • 我编辑我的问题。我希望现在更清楚了。

标签: php xml special-characters decode encode


【解决方案1】:

好的,以下内容现在有点粗略/冗长,尤其是您已经尝试了很多。试着保持新鲜的眼睛,想想一旦你在编码上犯了一个小错误,它通常就已经搞砸了。因此,重要的是要正确了解哪些机制在这里起作用。

我尝试解决在 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 UTF-8 编码在 XML 声明中没有指定&lt;?xml version="1.0"?&gt;

所以你可能会说“但我想要”,当然你可以。这就是调用构造函数时 DOMDocument 的 encoding 参数的作用:

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

如图所示,我们使用的第一个 (version) 和第二个 (encoding) 参数将被写出。所以是的,我们可以做不允许的事情。但是这个XML Declaration 允许什么? AFAIK 有一个 XML 版本,即 1.0。因此版本参数必须始终为 1.0。编码允许什么? XML 规范说 all the IANA characters sets,简而言之,它应该是以下常见规范之一(应该,不是必须):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"?>

编码按预期工作,版本是装饰性的,但它显示:这是使用编码为 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 实体 (&amp;#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 Character '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>

根据您查看输出的程序,它可能不会显示问号 - 而只是“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 为我建议您现在阅读的主题收集了一些有用的资源:

【讨论】:

  • 是的,成功了。将元标记放在我的 html 的标题中。我尝试了 php utf-8_encode 和解码,但返回了不同的字符,如 äé。再次感谢 hakre。现在我的网络应用已经准备好吃午饭了。
  • 非常好!这也是我认为你的问题,但我也想展示 DOMDocument 编码参数是如何工作的,这样你就可以更好地找到指定编码的位置(或者重新编码的位置,如果有的话)。顺便说一句,您使用哪个编辑器进行 xxx 显示?可能是 Notepad++ 吗?
  • Notepad++ 是一款不错的编辑器。如您所见,它甚至向您显示了错误编码字符的二进制序列(十六进制值)。这不仅仅是显示一个问号。您是否觉得 Notepdad++“太短了”或者您只是好奇?
  • 只是想知道是否有更好的编辑器。我以前有过深红色的编辑器,我必须说我更喜欢notepad++。我为 android 和 java 使用 eclipse,但我不知道什么是最好的编辑器。我看到很多同学都有黑屏编辑器,但我认为他们只是更改了编辑器中的背景和文本选项。
  • 好吧,如果你知道 eclipse,有一个 PHP 插件叫做 PDT。您可以获得的最好的 PHP IDE 称为 PHPStorm。所以这取决于你在哪里感觉更自在。还有支持 PHP 的 Netbeans,PHP IDE 几乎就是这样。我不能推荐 Zend 的 IDE/Editor(也是基于 Eclipse 的),而是坚持使用 PDT 或购买 PHPStorm 恕我直言。几年前用过深红,但放弃了。在 Windows 上,我使用一个名为 EditPlus 的编辑器。
猜你喜欢
  • 2017-01-11
  • 2012-11-07
  • 1970-01-01
  • 1970-01-01
  • 2011-05-09
  • 2021-08-08
  • 2015-07-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多