DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> XML學習教程 >> XML詳解 >> 使用PHP創建XForms 第2部分
使用PHP創建XForms 第2部分
編輯:XML詳解     

 本文示例源代碼或素材下載

  PHP XForms 庫:下一個任務是什麼?

  此時,您所擁有的 PHP 庫基本上可以正常運作,但是還未進行過測試。現在,我們來改善輸出的外觀、驗證函數的輸入(XForms 預處理器錯誤並非總是有用),並查看庫的操作演示。

  因此,現在開始執行這些任務。

  對庫進行增強

  庫的核心部分現已完成,因此可繼續對 PHP XForms 庫進行增強,比如構建一些簡單的拋出異常和處理異常的功能,這些功能會很有用,因為並非所有輸入的設置都可以接受,或者說在結果的 XHTML 文檔中會不可避免地出現錯誤。另外,您需要一些便利的函數將 XHtml 輸出到 Web 浏覽器,以及正確地處理數據縮進。我們從錯誤檢查開始介紹。

  錯誤檢查

  在本節中,通過向庫中添加錯誤檢查,可以減少 XForms 處理器中需要調試的錯誤,從而減少編程時間。處理完這一切後對編程有很大幫助。您將以兩種方式執行錯誤檢查:

  首先,對於允許使用子元素(如您在 第 1 部分 添加的最後四個 action、model、trigger 和 repeat)的 XHTML 標記,您要確保只有允許的 XHtml 標記才作為子元素添加。

  最後,您將對單個函數的輸入執行錯誤檢查,確保不出現某些情況,如果出現這些情況,則拋出一個異常,捕獲之並顯示在浏覽器上。

  首先,轉到 xforms_lib.PHP 類文件中的變量列表,添加另外兩個變量,如清單 1 所示。

  清單 1. 新變量...
  var $namespaceEvents;
  var $allowed;
  var $tag;
  
  function xforms_lib($ns, $nsxforms, $nsevents){
...
    $this->tag = '';
    $this->allowed =
      array('action' => array('dispatch', 'insert',
                  'setvalue', 'load'),
         'model' => array('instance', 'submission',
                  'bind', 'action'),
         'trigger' => array('label', 'action'),
         'root' => array('trigger', 'submit', 'select1',
                 'repeat', 'input', 'output',
                 'label', 'model'));
...
新變量是 $allowed 和 $tag 變量。在構造函數中,您將初始化這兩個變量。在本節中,稍後您將了解關於 $tag 變量的更多信息,但是可以這樣說,它保存了當前打開的標記的名稱。清單 1 中的每個值都是頂級的 XForms XHTML 標記。Root 在沒有進行任何指定時使用(repeat 和 root 一樣,所以當打開 repeat 標記時,root 用於此類錯誤檢查)。例如,查看一下 ‘action’:只有 dispatch、insert、setvalue 和 load 這四個 XHtml 標記可以作為子元素。每個標記各不相同,因此可以允許使用子元素的不同子集。

  接下來,您將修改 dispatchTag 方法以利用這種新功能,如清單 2 所示。

清單 2. 修改 dispatchTag 函數  function dispatchTag($name, $target){
    $this->check('dispatch');
    $XML = '<xforms:dispatch';
    if($name != '')
      $XML .= ' name="'.$name.'"';
    if($target != '')
      $XML .= ' target="'.$target.'"';
    $XML .= " />";
  }
請注意此處的新內容。您將創建的標記名稱傳給新函數 check(這個函數稍後將做定義)。其余部分應相同。

  現在,您將定義 check 函數,由此函數執行實際的檢查,如清單 3 所示。

  清單 3. check 函數

  function check($newTag, $action=''){
    $openTag = $this->tag;
    if($openTag == '')
      $openTag = 'root';
    if($action == 'close' && ($openTag != $newTag || $openTag == 'root'))
      throw new Exception("Cannot close $openTag with a $newTag ".
                ""close tag"statement!");
    else if($action == 'close' && $openTag == $newTag)
      return;
    else if(!in_array($newTag, $this->allowed["$openTag"]))
      throw new Exception("$newTag is not allowed within $openTag!");
  }

  第一個 if 語句:注意,如果空字符串 ('') 是 $tag 類變量的當前值,則 $openTag 參數默認為 ‘root’。

第二個 if 語句:如果 $openTag 中指定的打開標記已關閉,且打開標記($openTag)與關閉的標記($newTag)不同(或打開標記是 root 標記,因為後者不能被關閉),則會拋出一個錯誤。

  第一個 else if 語句:另一方面,如果關閉的標記($newTag)與打開標記($openTag)相等,則不會出現錯誤。

  第二個 else if 語句:盡管如此,如果打開的/創建的標記($newTag)不是當前打開標記($openTag)中允許打開的標記(比如,嘗試在 action 標記中創建的一個 repeat 標記),則會拋出一個錯誤。這裡錯誤將被捕獲並顯示給用戶。

  現在,您將使用 check 函數,方法是將 check 語句添加到函數的其余部分,清單 4 中顯示的部分內容可以作為您的指導(其余部分紗?源代碼下載 獲得)。

  清單 4. 添加 check 語句  function loadTag($resource = '', $ref = '', $show='replace'){
    $this->check('load');
    $XML = '<xforms:load show="'.$show.'"';
...
  }
  function triggerTagOpen($ref, $submission = '', $label = 'default'){
    $this->check('trigger', 'open');
    $XML = '<xforms:trigger ref="'.$ref.'"';
    if($submission != '')
      $XML .= ' submission="'.$submission.'"';
    $XML .= ' >';
  }
  function triggerTagClose(){
    $this->check('trigger', 'close');
    $XML = '</xforms:trigger>';
  }
這裡,您需要確保向所有創建 XHtml 標記的函數添加一個 $this->check() 函數調用。注意在 triggerTagOpen 和 triggerTagClose 函數中調用 check 函數的區別,在 triggerTagClose 函數中,需要根據標記的打開、關閉情況傳入第二個參數(‘open’ 或 ‘close’)。

  現在您將創建函數設置當前的打開標記($this->tag),目前 清單 3 中引用了該標記。您將使用此函數設置當前打開標記的值,如清單 5 所示。

清單 5. setTag 函數  function setTag($t){
    $this->tag = $t;
  }
您將使用此函數設置最高元素的標記。例如,在打開 model 標記後,您將這樣調用此函數:setTag('model')。在關閉標記後,您將不繼續在 XForms XHtml 標記下操作,而執行如下調用:setTag('root'),將當前的開放標記重新設置為 root。

  現在,系統出現錯誤時將通過拋出異常來驗證輸入。只有以下五個函數需要這種錯誤檢查功能:submission、bind、load、select1 和 instance。從 submission 開始介紹,如清單 6 所示。

  清單 6. submissionTag 函數:對輸入錯誤拋出異常  function submissionTag($id, $action, $method = 'post', $ref='',
              $instance = '', $replace = ''){
    $this->check('submission');
    if(($instance != '' || $replace != '') &&
      $replace != '' && $instance != '')
      throw new Exception("instance or replace is set, but not both ".
                "in a submission tag!");
    $XML = '<xforms:submission id="'.$id.'" action="'.$action.
      '" method="'.$method.'"';
...
  }
對於 tag 標記,$instance 或 $replace 參數可以分別設置,但是不可以同時設置。使用此函數時將拋出一個異常並顯示給用戶。

  該思想在其他四個函數中類似,如清單 7 所示。

清單 7. 對輸入錯誤拋出異常的更多函數  function bindTag($nodeset, $relevant = '', $calculate = '',
           $required = ''){
    $this->check('bind');
    if($relevant == '' && $calculate == '' && $required == '')
      throw new Exception("Must set one of: relevant, calculate or ".
                "required in a bind tag!");
    $XML = '<xforms:bind nodeset="'.$nodeset.'"';
...
  }
  function loadTag($resource = '', $ref = '', $show='replace'){
    $this->check('load');
    if($resource != '' && $ref != '')
      throw new Exception("Cannot specify both a resource and ref ".
                "for the load tag!");
    else if($resource == '' && $ref == '')
      throw new Exception("Must specify one of: resource or ref ".
                "for the load tag!");
    $XML = '<xforms:load show="'.$show.'"';
...
  }
  function select1Tag($ref, $label, $itemArray, $itemset){
    $this->check('select1');
    if(is_array($itemArray) && is_array($itemset))
      throw new Exception("Cannot specify both a list of items ".
                "and an itemset for a select1 element!");
    else if(!is_array($itemArray) && !is_array($itemset))
      throw new Exception("Must specify one of: itemArray or itemset ".
                "as arrays in the select1 tag!");
    $XML = '<xforms:select1 ref="'.$ref.'">';
    $XML .= '<xforms:label>'.$label.'</xforms:label>';
...
  }
  function instanceTag($id = '', $instanceXML = '', $src = ''){
    $this->check('instance');
    if($instanceXML != '' && $src != '')
      throw new Exception("Must define instance data or a src URL ".
                "for the instance tag!");
    $XML = '<xforms:instance';
...
  }
注意,bindTag 函數的輸入 $required、$calculate 或 $required 中,必須要設置其中一個。對於 loadTag 函數,$resource 和 $ref 輸入不能同時設置,但是必須設置其中一個。select1Tag 函數也需要設置 $itemArray 和 $itemset 中的一個但不能同時設置。最後,instanceTag 函數要求對 $instanceXML 和 $src 都不進行設置。

  至此,錯誤處理一節全部結束。稍後在測試一節中,您將了解如何處理拋出的錯誤並將錯誤消息顯示給用戶。

便利函數

  要完成錯誤處理,您需要添加幾個便利函數,幫助開發人員在 XForms 開發中使用 PHP。

  首先,您將再定義幾個類變量,如清單 8 所示。

  清單 8. 更多的類變量  var $allowed;
  var $print;
  var $indentation;
  var $indentationValue;
  
  function xforms_lib($ns, $nsxforms, $nsevents){
...
    $this->namespaceEvents = $nsevents;
    $this->print = 0;
    $this->indentation = 0;
    $this->indentationValue = "  ";
    $this->allowed =
...
  }
這裡創建了另外三個類變量以幫助格式化 XHTML 輸出。$print 變量指定是否使用 printData(稍後定義)在類函數中將 XHtml 直接輸出到浏覽器(用 echo 語句)。$indentation 變量指定了調用 indentation 函數(稍後定義)時所需輸出的縮進級數,$indentationValue 變量指定了需要顯示為縮進的內容(這裡有四個空間用作 $indentationValue)。

  現在,您將創建幾個函數設置 $print、$indentation 計數增減量的值,如清單 9 所示。

  清單 9. 修改 $indentation 和 $print 的函數  function incrementIndentation(){
    $this->indentation++;
  }
  function decrementIndentation(){
    $this->indentation--;
  }
  function setPrint($p){
    if($p)
      $this->print = 1;
    else
      $this->print = 0;
  }

  前兩個函數對構造函數中初始化為零的類變量 $indentation 進行增減,而第三個函數將 $print 設置為 1,前提是傳入的變量為 true;否則,$print 設置為 0。

下一個函數顯示了縮進,如清單 10 所示。

  清單 10. 顯示縮進  function indentation(){
    $XML = '';
    for($i = $this->indentation; $i > 0; $i--)
      $XML .= $this->indentationValue;
    return $XML;
  }
此函數需要迭代的次數與 $indentation 類變量值相同,對於每次迭代,它將 $indentationValue 類變量添加到 $xml,並將後者返回。因此,如果 $indentation 是 2,則在返回 $XML 之前將累計 8 個空間。此函數和 decrementIndentation 及 incrementIndentation 函數使得到的 XHtml 代碼具有正確的縮進格式。

  清單 11 展示了如何使用 printData 函數顯示 XHtml。

  清單 11. 顯示 XHtml

  function printData($XML){
    if($this->print){
      echo $this->indentation();
      echo $XML."rn";
      return 0;
    }
    return 1;
  }

  每個函數的末尾調用 printData 函數,根據 $print 類變量的值返回 XHtml 數據,或顯示到浏覽器。將其添加到所有的標記創建函數中,如清單 12 中的示例所示。將 incrementIndentation 函數添加到所有的 tagOpen 函數中,並將 decrementIndentation 添加到所有的 tagClose 函數中。

  清單 12. 使用 printData、incrementIndentation 和 decrementIndentation 函數  function submissionTag($id, $action, $method = 'post', $ref='',
              $instance = '', $replace = ''){
    $this->check('submission');
...
      $XML .= ' replace="'.$replace.'"';
    $XML .= " />";
    $this->printData($XML);
    return $XML;
  }
  function triggerTagOpen($ref, $submission = '', $label = 'default'){
    $this->check('trigger', 'open');
    $XML = '<xforms:trigger ref="'.$ref.'"';
    if($submission != '')
      $XML .= ' submission="'.$submission.'"';
    $XML .= ' >';
    $this->incrementIndentation();
    $this->printData($XML);
    return $XML;
  }
  function triggerTagClose(){
    $this->check('trigger', 'close');
    $XML = '</xforms:trigger>';
    $this->decrementIndentation();
    $this->printData($XML);
    return $XML;
  }

  這裡,您會發現上面 清單 12 中的每個函數都使用了 $this->printData 函數。注意,即使已經調用 printData 在浏覽器上顯示數據,XHtml 數據仍然會返回到調用函數的語句。還要注意,triggerTagOpen 函數使用 incrementIndentation 函數的方式。因此,在打開 trigger 標記後所有內容都將擁有額外的縮進,直至調用 triggerTagClose 關閉 trigger 標記。這將在調用 triggerTagOpen 函數之前將縮進減至原始值。

將 $this->printData($XML); 語句添加到函數其余部分的適當位置(您可以使用 源代碼下載 作為指導)。另外,將 $this->decrementIndentation(); 語句添加到所有的 tagClose 語句中,並將 $this->incrementIndentation(); 語句添加到所有的 tagOpen 語句中,使用 清單 12 和 源代碼下載 作為指導。

  最後,還有幾個便利函數讓您更輕松地使用 PHP XForms 庫,如清單 13 所示。您可以在 PHP 文件中使用這些函數顯示所需的常見 Html 標記。

  清單 13. 便利函數  function doctypeTag(){
    $XML = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHtml 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xHtml1-transitional.dtd">';
    $this->printData($XML);
    return $XML;
  }
  function headTitle($title){
    $XML = "<head><title>$title</title>";
    $this->printData($XML);
    return $XML;
  }
  function closeHeadOpenBody(){
    $XML = "</head><body>";
    $this->printData($XML);
    return $XML;
  }
  function closeBodyCloseHtml(){
    $XML = "</body></Html>";
    $this->printData($XML);
    return $XML;
  }
  function outputXHtmlheader(){
    header("Content-Type: application/xHtml+XML; charset=UTF-8");
  }

  在下一節中,您將使用上面的各個函數設置用於測試 XForms PHP 庫的表單(稍後創建)。它們只是創建標記,並輸出與 XHtml 兼容的報頭。

使用 PHP XForms 庫創建表單

  現在來看看這個 XForms PHP 庫的真正用途。在本節中將實例化幾個 XForms 小部件並使用 Firefox XForms 插件顯示其工作情況。

  首先查看一下新索引頁面的開頭,如清單 14 所示。

  清單 14:新索引頁面的開頭<?PHP
include('lib/xforms_lib.PHP');
$xformsDoc = new xforms_lib("http://www.w3.org/1999/xHtml",
              "http://www.w3.org/2002/xforms",
              "http://www.w3.org/2001/XML-events");
$xformsDoc->setPrint(1);
$xformsDoc->outputXHtmlheader();
$xformsDoc->doctypeTag();
$xformsDoc->HtmlTag();
$xformsDoc->incrementIndentation();
$xformsDoc->headTitle('XForms served via PHP');
...
?>

  第一行將庫包含到 PHP 文件中,在該文件中您將實例化一個新的 xforms_lib 類並傳入三個名稱空間。然後將 $print 類變量設為 1,直接將庫指定到輸出的 XHTML。然後通過輸出適當的報頭、文檔類型、HTML 標記和標題來設置 XHtml 文檔。

  接下來,您將查看如何使用庫創建 XForms 模型(見清單 15)。

  清單 15. 創建 XForms 模型...
// display model here
$model1 = 'model';
$instance1 = 'instance';
$instance1data = '<root XMLns=""><data1>../here</data1><data2/>'.
  '<data3/><data4/><data5/></root>';
$instance2 = 'instance2';
$instance2data = '<root XMLns=""><data><datum>data1</datum>'.
  '<datum>d2</datum><datum>third data</datum></data>
       </root>';
$submitButton1 = 'submit1';
$submitButton2 = 'submit2';
$xformsDoc->setTag('root');
$xformsDoc->modelTagOpen($model1);
$xformsDoc->setTag('model');
$xformsDoc->incrementIndentation();
$xformsDoc->instanceTag($instance1, $instance1data);
$xformsDoc->instanceTag($instance2, $instance2data);
$xformsDoc->submissionTag($submitButton1,
             "receive.PHP", 'post', "instance('$instance1')");
$xformsDoc->submissionTag($submitButton2,
             "receive.PHP", 'post', "instance('$instance2')");
$xformsDoc->bindTag("instance('$instance1')/data4",
          "instance('$instance1')/data3='1'",
          "instance('$instance1')/data2");
$xformsDoc->modelTagClose();
$xformsDoc->setTag('root');
$xformsDoc->decrementIndentation();
...

  前面幾行是 PHP 數據變量,其中包含了 model、instance 和 submission 名稱。另外還定義了兩個實例文檔 XML 數據。然後調用 setTag 將 $tag 類變量實例化為 ‘root’。

現在,您可以打開 model 標記,下一行中即完成了這一任務。$tag 變量然後被再次設為 ‘model’,因為剛打開了 model 標記,root 不再是頂級標記了。這也意味著需要增加縮進,因此調用 incrementIndentation。

  接下來實例化了兩個實例文檔,後接兩個 submission 標記。它們把使用 POST 發送的兩個實例文檔之一發送給 第 1 部分 中創建的 receive.PHP 頁面。還創建了一個 bind 標記,通過計算將 data4 (ref) 綁定到 data2 (calculate),而 data3 (relevant) 與 data4 相關。最後,關閉 model 標記,$tag 重置為 ‘root’ 並減少縮進。

  現在,您可以開始創建 XHtml 主體,如清單 16 所示。

  清單 16. 使用 inputTag 和 outputTag...
$xformsDoc->closeHeadOpenBody();
$xformsDoc->incrementIndentation();
// display form here
$xformsDoc->inputTag("instance('$instance1')//data1",
           'data1 (new page input): ');
echo "<br />";
$xformsDoc->inputTag("instance('$instance1')//data2",
           'data2 (data4 is bound to this fIEld): ');
echo "<br />";
$xformsDoc->inputTag("instance('$instance1')//data3",
           'data3 (1 makes data4 relevant): ');
echo "<br />data4 (bound to data2): ";
$xformsDoc->outputTag("instance('$instance1')//data4");
echo "<br />data5 (value of select menu shown here): ";
$xformsDoc->outputTag("instance('$instance1')//data5");
echo "<br />";
...

  首先關閉 XHtml head 標記,打開 body 標記。然後創建三個 input 標記,每個標記分別引用 $instance1 的 data1、data2 和 data3,接著創建兩個 output 標記,每個標記分別引用 $instance1 的 data4 和 data5。

您可以在表單中驗證使用這些值是否將使上面 清單 15 中創建的綁定元素按預期運作。

  下面您將定義一個 select1 標記,如清單 17 所示。

  清單 17. 定義 select1 標記...
$itemset['nodeset'] = "instance('$instance2')//datum";
$itemset['label'] = '.';
$itemset['value'] = '.';
$xformsDoc->select1Tag("instance('$instance1')//data5", 'select me',
            '', $itemset);
echo "<br />";
...

  首先,您要使用包含 $instance2 中所有數據元素的節點集設置 $itemset 數組。然後實例化 select1 標記並使其引用 $instance1 的 data5。另外要注意的是,使用 select1 標記將導致 清單 16 中定義的第二個 output 標記的值被相應地更改。

  接下來定義兩個提交按鈕。這兩個按鈕將允許您查看每個實例的實際 XML。如清單 18 所示。

  清單 18. 定義提交按鈕...
$xformsDoc->submitTag($submitButton1, 'SubmitTextBoxes');
echo "<br />";
$xformsDoc->submitTag($submitButton2, 'SubmitSelect');
echo "<br />";
...

  相應地作出標記後,您可以在文本框和 select1 菜單框中使用這些值,然後單擊每個提交按鈕查看 XML 中的值都有哪些。

  現在測試一個 trigger 標記,如清單 19 所示。

  清單 19. 實例化 trigger 標記...
$xformsDoc->triggerTagOpen("instance('$instance1')//data1", '', 'new page');
echo "<br />";
$xformsDoc->setTag('trigger');
$xformsDoc->actionTagOpen("DOMactivate");
$xformsDoc->setTag('action');
$xformsDoc->loadTag('', "instance('$instance1')/data1",
          'new');
$xformsDoc->actionTagClose();
$xformsDoc->setTag('trigger');
$xformsDoc->triggerTagClose();
$xformsDoc->setTag('root');
...

  這裡,您創建了一個 trigger 標記,其標簽為 ‘new page’。打開該標記後,您將 $tag 變量設為 ‘trigger’,並在 trigger 標記中創建一個 action 標記,此標記在 DOMactivate 事件中激活。在此標記中設置 $tag 為 ‘action’ 後,創建一個 load 標記根據 data1 的值加載一個新頁面(可以自由地使用 data1 的值並按下此觸發器)。最後,關閉 action 和 trigger 標記,並將 $tag 重置為 root。

最後測試的標記為 repeat,如清單 20 所示。

  清單 20. 創建 repeat...
echo "<br/>repeat data:";
$xformsDoc->repeatTagOpen("instance('$instance2')//datum", 'id1');
$xformsDoc->setTag('root');
$xformsDoc->outputTag(".");
$xformsDoc->setTag('repeat');
$xformsDoc->repeatTagClose();
$xformsDoc->setTag('root');
$xformsDoc->decrementIndentation();
$xformsDoc->decrementIndentation();
$xformsDoc->closeBodyCloseHtml();
?>

  這裡,您將 repeat 的內容指定為 $instance2 中的所有數據子元素。因為在添加新元素時,repeat 與 root 等效,因此您將 $tag 設為 ‘root’。然後您將顯示一個 output 標記,用於顯示當前 XML 數據內容的內容。然後在關閉 repeat 標記之前將 $tag 設為 ‘repeat’,關閉後,將 $tag 重置為 root。

  創建完所有的 XHTML XForms 標記後,通過兩次減少縮進值並關閉 body 和 html 標記來關閉 XHtml 文檔。

  您可以在圖 1 中預覽表單。

  圖 1. 最後的結果表單使用PHP創建XForms 第2部分

  確保右鍵單擊 XHTML 頁面並單擊 vIEw source,您就可以驗證 PHP 的 XHtml 輸出(見圖 2)。

  圖 2. 格式化工作使用PHP創建XForms 第2部分

  確保使用創建的 PHP 生成的 XForms 小部件處理表單。

  結束語

  祝賀您。您現在已經擁有了一個相當健壯的 PHP XForms 庫,您可以使用該庫繼續進行開發和擴展。注意,該庫和它定義的 XForms XHTML 標記並不一定完整,庫本身及其錯誤檢查功能仍然具有擴展的空間。例如,您可以定義一些新函數,在其中定義一些新的 XForms XHtml 標記。本質上講,一切皆有可能,整個開源項目就是基於開發人員的不懈努力,正如這個分兩部分的 系列文章 中介紹的那樣。盡情享受您的 PHP 和 XForms 之旅,祝您編程愉快!


 

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved