通过PHP使用XSLT进行UTF-8编码问题

rvd*_*vdb 2 php xslt encoding utf-8

通过PHP通过XSLT转换XML时,我遇到了一个令人讨厌的编码问题.

可以按如下方式总结/减少该问题:当我使用XSLT样式表复制(UTF-8编码的)XHTML文件时,某些字符显示错误.当我只显示相同的XHTML文件时,所有字符都正确显示.

以下文件说明了问题:

XHTML

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>encoding test</title>
    </head>
    <body>
        <p>This is how we d&#239;&#223;&#960;&#955;&#509; &#145;special characters&#146;</p>
    </body>
</html>
Run Code Online (Sandbox Code Playgroud)

XSLT

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

    <xsl:output method="xml" encoding="UTF-8"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)

PHP

<?php
  $xml_file = 'encoding_test.xml';
  $xsl_file = 'encoding_test.xsl';

  $xml_doc = new DOMDocument('1.0', 'utf-8');
  $xml_doc->load($xml_file);

  $xsl_doc = new DOMDocument('1.0', 'utf-8');
  $xsl_doc->load($xsl_file);

  $xp = new XsltProcessor();
  $xp->importStylesheet($xsl_doc);

  // alllow to bypass XSLT transformation with bypass=true request parameter
  if ($bypass = $_GET['bypass']) {
    echo file_get_contents($xml_file);
  }
  else {
    echo $xp->transformToXML($xml_doc);
  }
?>
Run Code Online (Sandbox Code Playgroud)

当这样的脚本被调用时(通过例如http://localhost/encoding_test/encoding_test.php),转换后的XHTML文档中的所有字符都可以正常显示,除了‘ 和’ 字符实体(它们是打开和关闭单引号).我不是Unicode专家,但有两件事让我感到震惊:

  1. 所有其它字符实体正确解释(这可能意味着一些事情的UTF-8的烦躁&#145;&#146;)
  2. 但是,当XHTML文件未显示时(例如http://localhost/encoding_test/encoding_test.php?bypass = true),所有字符都会正确显示.

我想我已经尽可能地为输出声明了UTF-8编码.其他人可能会看到什么是错的,可以被纠正吗?

提前致谢!

Ron Van den Branden

Dir*_*mar 10

&#145;并且&#146;没有可见的Unicode字符.

它们是用于单引号的旧HTML字符引用1,但是当您使用XSLT处理器处理它们时,处理器不会看到单引号,而是带有十进制代码145和146的Unicode字符,即U + 0090和U + 0091.

这些字符是私人使用(即使用不是由Unicode联盟定义)C1控制代码.

解决方案是使用正确的Unicode字符&#x2018;&#x2019;.

1 实际上,这些是映射到Windows-1252编码的代码.它们由浏览器显示,但实际上在HTML中无效:

注 - 上述SGML声明与HTML 2.0一样,将字符号128到159(十六进制为80到9F)指定为UNUSED.这意味着该范围内的数字字符引用(例如')在HTML中是非法的.ISO 8859-1和ISO 10646都不包含该范围内的字符,这些字符是为控制字符保留的.