3

I have some problems using xml. I know this is a comon question, but the answers i found didn't fix my problem. The problem is that when I add é or ä or another special char to my xml file, with php domdocument, it saves the é as xE9 and the ä as xE4. I don't know if this is ok but when I want to show the output it shows question marks at this places. I have tried alot. Like removing and adding the encoding in de xml header in the php domdocument. I also tried using file_get_contents and use php utf-8_decode to get the xml. I tried using iso intead, but nothing solved my problem. Instead I got php xml parse errors sometimes. I must do something wrong, but what? Thats my question and how I can solve this problem. My xml file looks like this: the xE9 and the xE4 have black backgrounds.

<?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>

and a part of my php xml class

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);
}       

this is the add new row function

//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);
}

everything works fine till I add spcial chars. Those are shown as questionmarks.

4

1 回答 1

6

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

我尝试解决在 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 version="1.0"?>显示默认的 XML UTF-8 编码: .

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

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

如图所示,我们使用的第一个(版本)和第二个(编码)参数将被写出。所以是的,我们可以做不允许的事情。但是这个XML 声明允许什么?AFAIK 有一个 XML 版本,即 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"?>

编码按预期工作,版本是装饰性的,但它显示:这是使用编码为 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 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 为我建议您现在阅读的主题收集了一些有用的资源:

于 2013-05-01T23:32:38.227 回答