XML 解析 - PHP 编码

Posted

技术标签:

【中文标题】XML 解析 - PHP 编码【英文标题】:XML Parsing - PHP encoding 【发布时间】:2014-10-12 00:23:09 【问题描述】:

我有一个很大的 XML (>15Mb),我必须读取它、解析它并将一些值存储在数据库中。我的问题是,XML 有不同的格式(UTF-8、ISO-8859-1)。

使用 UTF-8 没有问题。但是 ISO-8859-1 给我带来了巨大的问题!!标签带有特殊字符,XMLReader 和 readOuterXML() 无法正确解析

已经尝试过,但没有成功

$xml = new XMLReader;
$xml->open($import_file,'ISO-8859-1');  

试过了:

utf8_encode mb_convert_encoding($stringXML, 'UTF-8' ); iconv("ISO-8859-1", "UTF-8//TRANSLIT", $stringXML);

XML(简体)

标签(id)-->没问题 标签 (baños) --> 问题

xml:

<?xml version="1.0" encoding="ISO-8859-1"?>
<data>
    <id><![CDATA[5531]]></id>
    <baños><![CDATA[0]]></baños>
</data>

他们都没有帮助我。

【问题讨论】:

向我们展示实际的 xml 数据。尝试复制粘贴它,然后将无法解析的实际字符的十六进制转储。这将有助于确定问题。 @Evert XML 已上传!谢谢 好的,这是重要的一点!在命令行(或其他十六进制编辑器)上使用hex-dump -C 并找出用于ñ 字符的字节值。我们要确保它实际上是 ISO-8859-1,而不是别的什么。 @Evert 我得到了这个答案 。我的 ñ 被一个“。”改变了 hexdump 会自动将任何非 ascii 字符更改为 .。重要的部分在该行的前半部分,即实际代码。在那里你的ñ 变成了0x96。 0x96 在 ISO-8859-1 中不是有效的字符代码,在 CP-1252 中也不是。所以无论你的编码是什么,它都是别的东西! 【参考方案1】:

你在 php 中的内部编码是什么?您可以通过echo mb_internal_encoding();查看。

如果是 UTF-8,那么mb_convert_encoding($data, "UTF-8") 不会做任何事情,因为第三个参数$from_encoding 已经是“UTF-8”了。

您必须提供源编码作为函数的第三个参数。

所以也许这可以解决问题:

//check which encoding the data has? 
$encoding = mb_detect_encoding($data);
if($encoding != "UTF-8")
    //specify from which encoding to convert to utf-8
    $data = mb_convert_encoding($data, "UTF-8", $encoding); 

【讨论】:

mb_detect_encoding 的问题在于它不支持 MacRoman(此 XML 文件的实际编码)。支持的编码的完整列表可以在here找到。 @Tip-Sy,谢谢你的提示,我不知道这一点。所以如果它应该在纯 php 中完成,看起来你必须自己实现它。看起来这是一个示例实现:ctd-web.fr/blog/2011/02/18/…【参考方案2】:

我能够使用 Symfony 的 XmlEncoder 类 (https://github.com/symfony/Serializer) 成功解码给定的 xml。我将 xml 存储在 test.xml 文件中以保证正确的编码(因为我的 php 文件默认以 UTF-8 编码)。

$encoder = new Symfony\Component\Serializer\Encoder\XmlEncoder();
$data = $encoder->decode(file_get_contents('test.xml'), 'xml');
//$data = ['id' = 5531, 'baños' => 0]

【讨论】:

【参考方案3】:

如果 XML 标签中的特殊字符有问题,这里有一种在解析前清理标签的快速肮脏方法:

$xml = <<<END
<?xml version="1.0" encoding="ISO-8859-1"?>
<data>
    <id><![CDATA[5531]]></id>
    <baños><![CDATA[0]]></baños>
</data>
END;

function FilterXML($matches)

  return $matches[1] . preg_replace('/[^a-z]/ui', '_', $matches[2]) .
    $matches[3];


var_dump(preg_replace_callback('#(</?)([^!?]+?)(\\s|>)#', 'FilterXML', $xml));

它将用&lt;ba_os&gt;替换&lt;baños&gt;

【讨论】:

【参考方案4】:

正如@Evert 指出的,你的ñ 的字节码是:0x96,而你的XML 文件的编码实际上是MacRoman(see the table here)。

如果您想将数据转换为 UTF-8 格式,您需要执行以下操作:

$stringXML = file_get_contents('yourFile.xml');
$data = iconv('MACINTOSH', 'UTF-8', $stringXML);

另一种可能是使用 iconv 作为命令行:

iconv -f MACINTOSH -t UTF-8 file.xml > outputUTF8.xml

(这里是 Linux 库的链接:http://www.gnu.org/software/libiconv/)

【讨论】:

它将 转换为 如何获取 XML 文档的内容?您应该使用fopen 而不是XMLReader 或者干脆使用file_get_contents(见我编辑的答案)。效果更好吗? 我使用@file_get_contents('myurl/file.xml');得到它。 我必须在 php 服务器中使用它【参考方案5】:

您可以尝试先读取XML文件,然后转换特殊字符,再使用XMLReader读取XML字符串。

代码如下:

<?php
header("Content-Type: text/plain; charset=ISO-8859-1");
function normalizeChars($s)
    $replace = array(
        '&amp;' => 'and', '@' => 'at', '©' => 'c', '®' => 'r', 'À' => 'a',
        'Á' => 'a', 'Â' => 'a', 'Ä' => 'a', 'Å' => 'a', 'Æ' => 'ae','Ç' => 'c',
        'È' => 'e', 'É' => 'e', 'Ë' => 'e', 'Ì' => 'i', 'Í' => 'i', 'Î' => 'i',
        'Ï' => 'i', 'Ò' => 'o', 'Ó' => 'o', 'Ô' => 'o', 'Õ' => 'o', 'Ö' => 'o',
        'Ø' => 'o', 'Ù' => 'u', 'Ú' => 'u', 'Û' => 'u', 'Ü' => 'u', 'Ý' => 'y',
        'ß' => 'ss','à' => 'a', 'á' => 'a', 'â' => 'a', 'ä' => 'a', 'å' => 'a',
        'æ' => 'ae','ç' => 'c', 'è' => 'e', 'é' => 'e', 'ê' => 'e', 'ë' => 'e',
        'ì' => 'i', 'í' => 'i', 'î' => 'i', 'ï' => 'i', 'ò' => 'o', 'ó' => 'o',
        'ô' => 'o', 'õ' => 'o', 'ö' => 'o', 'ø' => 'o', 'ù' => 'u', 'ú' => 'u',
        'û' => 'u', 'ü' => 'u', 'ý' => 'y', 'þ' => 'p', 'ÿ' => 'y', 'Ā' => 'a',
        'ā' => 'a', 'Ă' => 'a', 'ă' => 'a', 'Ą' => 'a', 'ą' => 'a', 'Ć' => 'c',
        'ć' => 'c', 'Ĉ' => 'c', 'ĉ' => 'c', 'Ċ' => 'c', 'ċ' => 'c', 'Č' => 'c',
        'č' => 'c', 'Ď' => 'd', 'ď' => 'd', 'Đ' => 'd', 'đ' => 'd', 'Ē' => 'e',
        'ē' => 'e', 'Ĕ' => 'e', 'ĕ' => 'e', 'Ė' => 'e', 'ė' => 'e', 'Ę' => 'e',
        'ę' => 'e', 'Ě' => 'e', 'ě' => 'e', 'Ĝ' => 'g', 'ĝ' => 'g', 'Ğ' => 'g',
        'ğ' => 'g', 'Ġ' => 'g', 'ġ' => 'g', 'Ģ' => 'g', 'ģ' => 'g', 'Ĥ' => 'h',
        'ĥ' => 'h', 'Ħ' => 'h', 'ħ' => 'h', 'Ĩ' => 'i', 'ĩ' => 'i', 'Ī' => 'i',
        'ī' => 'i', 'Ĭ' => 'i', 'ĭ' => 'i', 'Į' => 'i', 'į' => 'i', 'İ' => 'i',
        'ı' => 'i', 'IJ' => 'ij','ij' => 'ij','Ĵ' => 'j', 'ĵ' => 'j', 'Ķ' => 'k',
        'ķ' => 'k', 'ĸ' => 'k', 'Ĺ' => 'l', 'ĺ' => 'l', 'Ļ' => 'l', 'ļ' => 'l',
        'Ľ' => 'l', 'ľ' => 'l', 'Ŀ' => 'l', 'ŀ' => 'l', 'Ł' => 'l', 'ł' => 'l',
        'Ń' => 'n', 'ń' => 'n', 'Ņ' => 'n', 'ņ' => 'n', 'Ň' => 'n', 'ň' => 'n',
        'ʼn' => 'n', 'Ŋ' => 'n', 'ŋ' => 'n', 'Ō' => 'o', 'ō' => 'o', 'Ŏ' => 'o',
        'ŏ' => 'o', 'Ő' => 'o', 'ő' => 'o', 'Œ' => 'oe','œ' => 'oe','Ŕ' => 'r',
        'ŕ' => 'r', 'Ŗ' => 'r', 'ŗ' => 'r', 'Ř' => 'r', 'ř' => 'r', 'Ś' => 's',
        'ś' => 's', 'Ŝ' => 's', 'ŝ' => 's', 'Ş' => 's', 'ş' => 's', 'Š' => 's',
        'š' => 's', 'Ţ' => 't', 'ţ' => 't', 'Ť' => 't', 'ť' => 't', 'Ŧ' => 't',
        'ŧ' => 't', 'Ũ' => 'u', 'ũ' => 'u', 'Ū' => 'u', 'ū' => 'u', 'Ŭ' => 'u',
        'ŭ' => 'u', 'Ů' => 'u', 'ů' => 'u', 'Ű' => 'u', 'ű' => 'u', 'Ų' => 'u',
        'ų' => 'u', 'Ŵ' => 'w', 'ŵ' => 'w', 'Ŷ' => 'y', 'ŷ' => 'y', 'Ÿ' => 'y',
        'Ź' => 'z', 'ź' => 'z', 'Ż' => 'z', 'ż' => 'z', 'Ž' => 'z', 'ž' => 'z',
        'ſ' => 'z', 'Ə' => 'e', 'ƒ' => 'f', 'Ơ' => 'o', 'ơ' => 'o', 'Ư' => 'u',
        'ư' => 'u', 'Ǎ' => 'a', 'ǎ' => 'a', 'Ǐ' => 'i', 'ǐ' => 'i', 'Ǒ' => 'o',
        'ǒ' => 'o', 'Ǔ' => 'u', 'ǔ' => 'u', 'Ǖ' => 'u', 'ǖ' => 'u', 'Ǘ' => 'u',
        'ǘ' => 'u', 'Ǚ' => 'u', 'ǚ' => 'u', 'Ǜ' => 'u', 'ǜ' => 'u', 'Ǻ' => 'a',
        'ǻ' => 'a', 'Ǽ' => 'ae','ǽ' => 'ae','Ǿ' => 'o', 'ǿ' => 'o', 'ə' => 'e',
        'Ё' => 'jo','Є' => 'e', 'І' => 'i', 'Ї' => 'i', 'А' => 'a', 'Б' => 'b',
        'В' => 'v', 'Г' => 'g', 'Д' => 'd', 'Е' => 'e', 'Ж' => 'zh','З' => 'z',
        'И' => 'i', 'Й' => 'j', 'К' => 'k', 'Л' => 'l', 'М' => 'm', 'Н' => 'n',
        'О' => 'o', 'П' => 'p', 'Р' => 'r', 'С' => 's', 'Т' => 't', 'У' => 'u',
        'Ф' => 'f', 'Х' => 'h', 'Ц' => 'c', 'Ч' => 'ch','Ш' => 'sh','Щ' => 'sch',
        'Ъ' => '-', 'Ы' => 'y', 'Ь' => '-', 'Э' => 'je','Ю' => 'ju','Я' => 'ja',
        'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd', 'е' => 'e',
        'ж' => 'zh','з' => 'z', 'и' => 'i', 'й' => 'j', 'к' => 'k', 'л' => 'l',
        'м' => 'm', 'н' => 'n', 'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's',
        'т' => 't', 'у' => 'u', 'ф' => 'f', 'х' => 'h', 'ц' => 'c', 'ч' => 'ch',
        'ш' => 'sh','щ' => 'sch','ъ' => '-','ы' => 'y', 'ь' => '-', 'э' => 'je',
        'ю' => 'ju','я' => 'ja','ё' => 'jo','є' => 'e', 'і' => 'i', 'ї' => 'i',
        'Ґ' => 'g', 'ґ' => 'g', 'א' => 'a', 'ב' => 'b', 'ג' => 'g', 'ד' => 'd',
        'ה' => 'h', 'ו' => 'v', 'ז' => 'z', 'ח' => 'h', 'ט' => 't', 'י' => 'i',
        'ך' => 'k', 'כ' => 'k', 'ל' => 'l', 'ם' => 'm', 'מ' => 'm', 'ן' => 'n',
        'נ' => 'n', 'ס' => 's', 'ע' => 'e', 'ף' => 'p', 'פ' => 'p', 'ץ' => 'C',
        'צ' => 'c', 'ק' => 'q', 'ר' => 'r', 'ש' => 'w', 'ת' => 't', '™' => 'tm',
        'ñ' => 'n',
    );
    return strtr($s, $replace);


$path_to_file = '';
$xml_text = @file_get_contents($path_to_file);
if(!empty($xml_text))
    $xml_text = normalizeChars($xml_text);
    $xml = new XMLReader();
    $xml->XML($xml_text);

?>

另一方面,如果您正在寻找性能,那么您应该尝试 SimpleXML 和 DOM Document,如以下 *** 问题中所述:https://***.com/a/1835324/1337185

编辑:

我添加了header("Content-Type: text/plain; charset=ISO-8859-1"),因为strtr 仅适用于 ISO-8859-1。 我使用 OP 提供的 XML 字符串进行了尝试,它运行良好。如果有任何缺失的字符,请随时将其添加到数组中。

【讨论】:

我已经这样做了:但不替换字符... $content = @file_get_contents("www.path.com/file.xml"); $content = $this->normalizeChars($content); echo "替换完成!"; $newxml = simplexml_load_string($content); print_r($newxml); 我很高兴它成功了。如果您认为它解决了您的问题,请对答案投票。 不.. @Wissam El-Kik 我写了“不替换字符”。它没有解决我的问题。 @user2855036 我刚刚意识到strtr 需要一个字符集 ISO-8859-1。现在它应该可以工作了。 这是一种在解析之前修改源代码的技巧,通常不能解决底层编码问题。您应该使用 iconv 而不是试图重新发明***。为什么'ת'应该映射到't'而不是'n'?如果你这样做,就没有语义。

以上是关于XML 解析 - PHP 编码的主要内容,如果未能解决你的问题,请参考以下文章

PHP中SimpleXMLElement对象字符编码

使用 PHP 和 XMLReader 解析 XML

PHP:simplexml_load_file 从使用 UTF-8 编码的 XML 文件中获取奇怪的字符

使用非utf-8编码在Python中解析XML

在 Python 中解析 XML 时出现编码问题

使用来自网络的编码 ISO-8859-1 解析 XML