2010-09-08 22 views
2

當通過PHP通過XSLT轉換XML時,我正面臨一個討厭的編碼問題。通過PHP使用XSLT的UTF-8編碼問題

這個問題可以概括如下:當我用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> 

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> 

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

當這個腳本調用本身(例如通過http://localhost/encoding_test/encoding_test.php),轉換後的XHTML文檔中的所有字符都沒問題,除了&#145;和&#146;字符實體(它們打開和關閉單引號)。我不是一個Unicode專家,但兩件事情打我:

  1. 所有其它字符實體正確(這可能意味着一些有關&#145;的UTF-8的煩躁和&#146;)解釋
  2. 然而,當XHTML文件顯示不中介(通過例如http://localhost/encoding_test/encoding_test.php?bypass=true),全部字符顯示正確。

我想我已經在任何地方聲明瞭UTF-8編碼。別人可能會看到有什麼不對,並可能被糾正?

在此先感謝!

羅恩·範登布蘭登

回答

10

&#145;&#146;都沒有明顯的Unicode字符。

他們是舊的HTML字符引用單引號,但是當你使用XSLT處理器,處理它們的處理器並沒有看到單引號,但在Unicode字符與十進制代碼145和146,即U+0090 and U+0091

這些字符是私人使用的(即,使用不由Unicode聯盟定義)C1 control codes

解決方法是使用正確的Unicode字符&#x2018;&#x2019;

實際上,這些是映射到Windows-1252編碼的代碼。它們是由瀏覽器顯示的,實際上卻是not valid in HTML

注 - 上面的SGML聲明,就像HTML 2.0的, 指定字符數128至159(80至9F十六進制) 爲未使用。這意味着該範圍內的數字字符引用 (例如’)在HTML中是非法的。 ISO 8859-1和ISO 10646均不包含 範圍內的字符,該字符保留用於控制字符。

+0

+1很好的解釋!同樣適用於其他字形的參考文獻http://en.wikipedia.org/wiki/Quotation_mark_glyphs – 2010-09-08 13:09:11

+0

HTML 5草案更進一步:「上述數字字符參考表單允許引用除U + 0000,U + 000D,永久未定義的Unicode字符(非字符)以及空格字符以外的控制字符。「 – Artefacto 2010-09-08 13:19:22

+0

唷,非常感謝!除了清楚的解釋之外,您非常樂意提供有用的解決方案。 – rvdb 2010-09-08 13:53:25