1

我正在将表格数据导出到 xml 中,其中在内容列中包含多语言内容,并混合了 html,例如

$xmlWriter->writeAttribute('value', $contents);

记录:

name="testing" , contents="Just <span style="color:red">testing</span>:漢字"

导出为:

<entry key="testing" value="Just &lt;span style='color:red'&gt;testing&lt;/span&gt;:&#x6F22;&#x5B57;">

预期的:

<entry key="testing" value="Just &lt;span style='color:red'&gt;testing&lt;/span&gt;:漢字">

我不希望 xml 编写器对多语言字符进行编码,这怎么可能?

4

1 回答 1

3

我不希望 xml 编写器对多语言字符进行编码,这怎么可能?

实际上,当您编写 XML 时,您已经进行了编码。您的意思是您不想对这两个字符使用数字实体,这是可能的,但并非总是如此。

要不使用数字实体,您需要将文档的编码与字符串的编码相匹配。从您提供的输出中,我只能猜测一下,这两个字符可能代表:

  1. Unicode 汉字'中国人,中文' (U+6F22)
  2. Unicode 汉字'字母、字符、单词' (U+5B57)

这可能意味着(到目前为止我不会说任何中文)像Chinese Word 之类的东西。

每当文档的编码无法在文档中表示该字符时,PHP 中的 XMLWriter 将始终将字符放入数字实体中(例如&#x6F22;和您的示例中)。&#x5B57;

如果您能够匹配两种编码,XMLWriter 将自动不使用数字实体。

我举一个更简单的例子。让我们将 Äpfel 中的编码US-ASCII德语变音符号(Unicode Character 'LATIN CAPITAL LETTER A WITH DIAERESIS' (U+00C4))作为属性值:Ä

<?php
$xmlWriter = new XMLWriter();
$xmlWriter->openMemory();
$xmlWriter->startDocument('1.0', 'US-ASCII');
$xmlWriter->startElement('root');
$xmlWriter->writeAttribute('value', 'Äpfel');
$xmlWriter->endDocument();
echo $xmlWriter->flush();

写在 UTF-8 编码的 PHP 文件中的这段代码将在执行时输出:

<?xml version="1.0" encoding="US-ASCII"?>
<root value="&#196;pfel"/>

&#196;是 unicode 字符 U+00C4 的数字实体,如果仔细观察,C4 是十进制 196 的十六进制表示,这也表明数字 XML 实体始终表示 Unicode 字符编号。

因此,XML 输出使用 US-ASCII 编码,该编码无法表示ÄPHP 代码中的 UTF-8 编码字符串,因此使用数字实体对其进行正确编码以保留字符信息。

现在更改编码:

$xmlWriter->startDocument('1.0', 'US-ASCII');

到 PHP 字符串的 UTF-8 编码:

$xmlWriter->startDocument('1.0', 'UTF-8');

确实改变了这个输出:

<?xml version="1.0" encoding="UTF-8"?>
<root value="Äpfel"/>

这同样适用于您的示例,但是,您的问题中缺少一个重要信息:该记录中的字符串采用哪种编码?

如果它已经是 UTF-8,那么就像我在上面的示例中概述的那样,它已经可以工作了:

<?php
$recordUTf8 = "... contents=\"Just <span style=\"color:red\">testing</span>:"
             ."\xE6\xBC\xA2\xE5\xAD\x97\"";
$encoding   = 'UTF-8';
$encoding   = 'US-ASCII';

$xmlWriter = new XMLWriter();
$xmlWriter->openMemory();
$xmlWriter->startDocument('1.0', $encoding);
$xmlWriter->startElement('record');
$xmlWriter->writeAttribute('value', $recordUTf8);
$xmlWriter->endDocument();
echo $xmlWriter->flush();

输出:

<?xml version="1.0" encoding="UTF-8"?>
<record value="... contents=&quot;Just &lt;span style=&quot;color:red&quot;&gt;
               testing &lt;/span&gt;:漢字 &quot;"/>

如此输出所示,此处未使用数字实体,但是,字符串显然是 UTF-8 编码的(此处以二进制安全的方式进行,以防您在复制 PHP 文件时使用不同的编码)。

所以在这里总结一下:XML 编码需要匹配字符串的编码来表示所有不在数字实体中的字符(除了那些用于对 XML 本身进行编码的字符,如、<>和)。'"&

这些几乎是 XML 基础知识。如果文档具有无法表示字符数据的编码,但由于 XML 支持 Unicode,则回退是数字实体。您正试图通过将文档编码与字符串编码对齐来防止这种回退。

这是我对 PHP 和 XMLWriter 的具体建议:

  1. 从数据库中获取记录或将记录重新编码为 UTF-8。
  2. 仅将 UTF-8 字符串传递给XMLWriter方法。
  3. 将 XML 文档编码设置为 UTF-8。

我给出这些建议是因为 UTF-8 是 XML 的默认编码,而 PHP 对 UTF-8 的支持非常好。XMLWriter 还期望 Unicode 字符串是 UTF-8 编码的,没有设置或选项可以让您更改它,因此输入已经需要 UTF-8 编码。

不管输入字符串如何独立,您自然可以告诉 XMLWriter 使用不同的输出编码。例如,任何其他中文或 Unicode 编码可能适合您,并且只要您的 PHP 配置支持特定的输出编码(检查您拥有的 iconv 库),XMLWriter 输出就可以。

当您使用 XMLWriter 启动文档时,第二个参数指定编码:

$xmlWriter->startDocument('1.0', $encoding);

您可以在相应的 XML 声明中放入 XML 支持的编码集中的任何编码:

<?xml version="1.0" encoding="ISO-8859-1"?><!-- Latin-1 example -->

XML 编码值的完整规范可以在这里找到: http: //www.w3.org/TR/REC-xml/#NT-EncName ::

在编码声明中,值“ UTF-8”、“ UTF-16”、“ ISO-10646-UCS-2”和“ ISO-10646-UCS-4”应用于 Unicode/ISO/IEC 10646 的各种编码和转换,值“ ISO-8859-1”、“ ISO-8859-2”、...“ ISO-8859-n” (其中 n 是零件编号)应用于 ISO 8859 的零件,并且值“ ISO-2022-JP”、“ Shift_JIS”和“EUC-JP" 应用于 JIS X-0208-1997 的各种编码形式。建议在 Internet 编号分配机构 [IANA-CHARSETS] 注册的字符编码(作为字符集),除了刚刚列出的那些,参考使用它们的注册名称;其他编码应使用以“x-”前缀开头的名称。XML 处理器应以不区分大小写的方式匹配字符编码名称,并且应将 IANA 注册名称解释为在 IANA 为该名称注册的编码,或者将其视为未知(当然,处理器不需要支持所有 IANA 注册的编码)。

其中 [IANA-CHARSETS] 是:

(Internet Assigned Numbers Authority)字符集的正式名称,编辑。凯尔德西蒙森等人。(参见http://www.iana.org/assignments/character-sets。)

这些规范可能有点冗长。在您的问题的上下文中,您需要做的就是找出记录字符串的编码。我顺便说一句。不能说我无法重现您的确切输出,我总是得到十进制实体,而不是十六进制实体。您也许可以通过string 的十六进制转储提供更多信息。

于 2013-09-19T09:37:21.097 回答