2011-01-25 67 views
3

我讀過這篇着名的文章。我看到了這些嘗試,無論是有限的成功還是失敗。哦,在這裏和其他地方的火焰戰爭。用正則表達式解析XML/XHTML數據

但它可以做到。

雖然我知道實際的參數(讀事實)是正則表達式不適合解析結構化數據樹,但由於它們無法監視和更改狀態,所以我覺得有些人會盲目放棄這種可能性。應用邏輯必須保持狀態,但正如工作示例所示,它可以完成。

相關片段如下:

const PARSE_MODE_NEXT = 0; 
const PARSE_MODE_ELEMENT = 1; 
const PARSE_MODE_ENTITY = 3; 
const PARSE_MODE_COMMENT = 4; 
const PARSE_MODE_CDATA = 5; 
const PARSE_MODE_PROC = 6; 

protected $_parseModes = array(
     self::PARSE_MODE_NEXT  => '% < (?: (?: (?<entity>!) (?: (?<comment>--) | (?<cdata>\[CDATA\[))) | (?<proc>\?))? %six', 
     self::PARSE_MODE_ELEMENT => '% (?<close>/)? (?<element> .*?) (?<empty> /)? > (?<text> [^<]*) %six', 
     self::PARSE_MODE_ENTITY => '% (?<entity> .*?) > (?<text> [^<]*) %six', 
     self::PARSE_MODE_COMMENT => '% (?<comment> .*?) --> (?<text> [^<]*) %six', 
     self::PARSE_MODE_CDATA => '% (?<cdata> .*?) \]\]> (?<text> [^<]*) %six', 
     self::PARSE_MODE_PROC  => '% (?<proc> .*?) \?> (?<text> [^<]*) %six', 
    ); 

public function load($string){ 
    $parseMode = self::PARSE_MODE_NEXT; 
    $parseOffset = 0; 
    $context = $this; 
    while(preg_match($this->_parseModes[$parseMode], $string, $match, PREG_OFFSET_CAPTURE, $parseOffset)){ 
     if($parseMode == self::PARSE_MODE_NEXT){ 
      switch(true){ 
       case (!($match['entity'][0] || $match['comment'][0] || $match['cdata'][0] || $match['proc'][0])): 
        $parseMode = self::PARSE_MODE_ELEMENT; 
        break; 
       case ($match['proc'][0]): 
        $parseMode = self::PARSE_MODE_PROC; 
        break; 
       case ($match['cdata'][0]): 
        $parseMode = self::PARSE_MODE_CDATA; 
        break; 
       case ($match['comment'][0]): 
        $parseMode = self::PARSE_MODE_COMMENT; 
        break; 
       case ($match['entity'][0]): 
        $parseMode = self::PARSE_MODE_ENTITY; 
        break; 
      } 
     }else{ 
      switch($parseMode){ 
       case (self::PARSE_MODE_ELEMENT): 
        switch(true){ 
         case (!($match['close'][0] || $match['empty'][0])): 
          $context = $context->addChild(new ZuqMLElement($match['element'][0])); 
          break; 
         case ($match['empty'][0]): 
          $context->addChild(new ZuqMLElement($match['element'][0])); 
          break; 
         case ($match['close'][0]): 
          $context = $context->_parent; 
          break; 
        } 
        break; 
       case (self::PARSE_MODE_ENTITY): 
        $context->addChild(new ZuqMLEntity($match['entity'][0])); 
        break; 
       case (self::PARSE_MODE_COMMENT): 
        $context->addChild(new ZuqMLComment($match['comment'][0])); 
        break; 
       case (self::PARSE_MODE_CDATA): 
        $context->addChild(new ZuqMLCharacterData($match['cdata'][0])); 
        break; 
       case (self::PARSE_MODE_PROC): 
        $context->addChild(new ZuqMLProcessingInstruction($match['proc'][0])); 
        break; 
      } 
      $parseMode = self::PARSE_MODE_NEXT; 
     } 
     if(trim($match['text'][0])){ 
      $context->addChild(new ZuqMLText($match['text'][0])); 
     } 
     $parseOffset = $match[0][1] + strlen($match[0][0]); 
    } 

} 

是否完整?沒有。

它是否牢不可破?當然不是。

它快嗎?沒有進行基準測試,但我無法想象它的速度如同DOM一樣快。

它支持XPath/XQuery嗎?顯然不是。

它驗證或執行任何其他輔助任務嗎?當然沒有。

它會取代DOM嗎?地獄號碼。

但是,它會解析這個嗎?

<?xml version="1.0" encoding="utf-8"?> 
<!ENTITY name="value"> 
<root> 
    <node> 
     <node /> 
     Foo 
     <node name="value"> 
      <node>Bar</node> 
     </node> 
     <!-- Comment --> 
    </node> 
    <node> 
     <[CDATA[ Character Data ]]> 
    </node> 
</root> 

是。是的,它會。

儘管我會歡迎該主題成爲社區Wiki,只要它滿足要求,我會將此語句轉換爲一個問題。

專注於正則表達式,任何人都可以預見這種情況下,如果使用格式良好的標記,這種情況會失敗嗎?我想我已經涵蓋了所有的基地。

我不打算「攪拌鍋」,但我希望從硬幣的兩側都有一些見解。

請注意,寫這個的目的是SimpleXML太簡單了,DOM對於我的一個應用程序來說太嚴格了。

回答

1

着眼於正則表達式,任何人都可以預見的情況下,這對形成良好的標記使用時,這將可怕的失敗?當對XML一致性測試套件運行,有多少格式良好的XML文檔它拒絕,以及它接受了多少不合格的XML文檔?

也許來自那些共享XML社區文化的人最大的反對意見是,它不僅會解析大多數格式良好的XML文檔,還會解析大多數非XML文檔,因爲它不會不告訴你他們是不合格的。現在,也許你認爲不要緊,在你的環境中太多 - 但最終,如果你接受病態的文件,那麼人們就會開始發送你生病形成文件,不久你是在同一個混亂的HTML ,因爲遺留原因您必須接受任何舊垃圾。

我不知道夠不夠PHP來判斷你的代碼將很快如何工作對格式良好的XML。但我懷疑的動機 - 爲什麼一個地球,你會想手工寫廉價和骯髒並慢XML解析器時,有現貨供應非常好和正確和快速的和釋放的人?

+0

當你提出一些不容爭辯的點,主要的原因已經寫了這個有:`SimpleXML`太簡單了,我需要的東西,提供有限的支持; `DOM`太嚴格了,導致比解決問題更多的問題;我需要一些適合遷移的東西,無論環境限制如何,都可以輕鬆納入任何項目。爲了達到目的,我不關心驗證,只關心解析和重構結構化文檔的能力。 *但是*,速度是一個問題,而在比`超過30倍慢(100,000測試迭代)DOM`,失敗,且無法使用。 :( – Dan 2011-01-26 20:13:22