2013-03-18 85 views
3

我目前正在重寫一個PHP類,試圖將XML文件拆分爲更小的塊,以使用XMLReader和XMLWriter而不是當前的基本文件系統和正則表達式方法。PHP XMLReader,獲取版本和編碼

但是,我無法弄清楚如何從XML序言中獲取版本,編碼和獨立標誌。

我測試的XML文件的開頭是這樣的:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE fakedoctype SYSTEM "fake_doc_type.dtd"> 

<!-- 
This is a comment, it's here to try and get the parser to break in some way 
--> 

<root attribute="value" otherattribute="othervalue"> 

我可以打開它沒關係與讀寫器,並通過文件具有讀取移動(),未來()等,但我可以」 t似乎得到了<?xml ... ?>中的任何東西。我能夠訪問的第一件事是僞造的DOCTYPE。

我的測試代碼如下:

$a = new XMLReader(); 
var_dump ($a -> open ('/path/to/test/file.xml')) // true 
var_dump ($a -> nodeType); // 0 
var_dump ($a -> name); // "" 
var_dump ($a -> readOuterXML()); // '' 
var_dump ($a -> read()); // true 
var_dump ($a -> nodeType); // 10 
var_dump ($a -> readOuterXML()); // <!DOCTYPE fakedoctype SYSTEM "fake_doc_type.dtd"> 

當然,我可能只是總是假設XML 1.0,UTF8編碼和獨立= YES,但對於正確性的緣故,我真的相當能抓住會源數據源中的值是什麼,並在生成分割文件時使用它們。

有關XMLReader和XMLwriter的文檔似乎非常差,所以我很有機會錯過了文檔中的某些內容。有沒有人知道在這種情況下要做什麼?

+2

是的,文檔很差。我只能找到非常一般的信息,_「重要的是要注意,在內部,libxml使用UTF-8編碼,因此,檢索內容的編碼將始終採用UTF-8編碼。」 - - 但沒辦法檢索有關原始文檔的信息。如果沒有其他解決方案出現,我可能會單獨閱讀文檔的第一行,並使用RegExp手動解析該信息(如果它很重要)。 – CBroe 2013-03-18 13:37:40

回答

3

我從XMLReader得知,即使它有XMLReader::XML_DECLARATION常量,我在XMLReader::$nodeType屬性中使用XMLReader::read()遍歷文檔時從未遇到過。

它看起來像被跳過了,我也想知道爲什麼這是,我還沒有找到任何標誌或選項來改變這種行爲。

對於輸出,XMLReader總是返回UTF-8編碼的字符串。這與PHP中其他基於libxml的部分是一樣的。所以從這一方面來說,一切都很清楚。但我認爲這不是你感興趣的部分,而是你用XMLReader::open()打開的文件中的具體字符串輸入。

不是專門針對XMLReader我曾經創建過a utility class I named XMLRecoder,它能夠檢測基於XML聲明和基於BOM的XML字符串的編碼。我認爲你應該這樣做。這是我認爲你仍然需要使用正則表達式的一部分,但是由於XML聲明必須是第一件事,它也是一個處理指令(PI),您應該可以在其中查看。

這是一些相關的部分來自XMLRecoder代碼:

### excerpt from https://gist.github.com/hakre/5194634 

/** 
* pcre pattern to access EncodingDecl, see <http://www.w3.org/TR/REC-xml/#sec-prolog-dtd> 
*/ 
const DECL_PATTERN = '(^<\?xml\s+version\s*=\s*(["\'])(1\.\d+)\1\s+encoding\s*=\s*(["\'])(((?!\3).)*)\3)'; 
const DECL_ENC_GROUP = 4; 
const ENC_PATTERN = '(^[A-Za-z][A-Za-z0-9._-]*$)'; 

... 

($result = preg_match(self::DECL_PATTERN, $buffer, $matches, PREG_OFFSET_CAPTURE)) 
    && $result = $matches[self::DECL_ENC_GROUP]; 

由於這表明它去,直到編碼,所以它是不完整的。然而,對於需要提取編碼(和您的需求版本),它應該做的工作。我已經對一噸(數千)隨機XML文檔進行了測試。

另一部分是BOM檢測:

### excerpt from https://gist.github.com/hakre/5194634 

const BOM_UTF_8 = "\xEF\xBB\xBF"; 
const BOM_UTF_32LE = "\xFF\xFE\x00\x00"; 
const BOM_UTF_16LE = "\xFF\xFE"; 
const BOM_UTF_32BE = "\x00\x00\xFE\xFF"; 
const BOM_UTF_16BE = "\xFE\xFF"; 

... 

/** 
* @param string $string string (recommended length 4 characters/octets) 
* @param string $default (optional) if none detected what to return 
* @return string Encoding, if it can not be detected defaults $default (NULL) 
* @throws InvalidArgumentException 
*/ 
public function detectEncodingViaBom($string, $default = NULL) 
{ 
    $len = strlen($string); 

    if ($len > 4) { 
     $string = substr($string, 0, 4); 
    } elseif ($len < 4) { 
     throw new InvalidArgumentException(sprintf("Need at least four characters, %d given.", $len)); 
    } 

    switch (true) { 
     case $string === self::BOM_UTF_16BE . $string[2] . $string[3]: 
      return "UTF-16BE"; 

     case $string === self::BOM_UTF_8 . $string[3]: 
      return "UTF-8"; 

     case $string === self::BOM_UTF_32LE: 
      return "UTF-32LE"; 

     case $string === self::BOM_UTF_16LE . $string[2] . $string[3]: 
      return "UTF-16LE"; 

     case $string === self::BOM_UTF_32BE: 
      return "UTF-32BE"; 
    } 

    return $default; 
} 

隨着BOM檢測我也沒有針對相同的XML文檔集運行這一點,但是,沒有多少人用的材料明細表。如您所見,檢測順序針對更常見的情況進行了優化,同時處理不同BOM之間的重複二進制模式。我遇到的大多數文檔都沒有BOM,您主要需要查看文檔是否爲UTF-32編碼。

希望這至少給出一些見解。

+0

考慮到所涉及的工作與收益相關,我認爲最好假設UTF8。如果事實證明這還不夠,我一定會回到這個答案。老實說,我現在比XMLreader和XMLwriter更大的問題了。 :)與他們合作並不愉快。 – GordonM 2013-03-19 09:45:18

+0

那麼如果你使用'XMLReader',我可以建議你一個項目,我運行它的名爲[* XMLReaderIterator *](http://git.io/xmlreaderiterator),它提供了很好的XMLReader接口和解決問題使用泛型編程(迭代器):['XMLReaderIterator' Github repro](https://github.com/hakre/XMLReaderIterator),並且還有一個正在進行的單一文件['XMLReaderIterator' gist release](https:// gist。 github.com/hakre/5147685) - 也許這很有幫助。此外,如果你可以把你的問題變成更通用的問題,那麼這裏會很棒,我們需要更多基於XMLReader的QA :)。 – hakre 2013-03-19 09:56:06

+0

我想說我們真正能做的是在php.net上爲XMLReader和XMLWriter編寫適當的文檔。 :)它遠沒有接近其他文檔的標準。 – GordonM 2013-03-19 10:02:50