html協議是基於文本的, 所以文本資料的傳遞是比較可靠的, 更重要的是JavaScript和PHP處理位元據都非常麻煩, 所以把各類資料使用文本的方式傳遞是一個首選方式.
大多數情況下我們需要傳遞比較複雜的內容, 這些文本需要進行解析才能使用, 雖然解析方式依賴具體的應用, 但是使用最多的仍然是字典格式的數組, 也就是 key = value 這種方式, 比如參數的傳遞. 更複雜的, 可能需要多級資料. 樹形資料是應用最多的情況, 這裡實現了樹形資料的打包和解析. 需要注意的是, 如果使用ajax傳遞資料,
還需要對這些資料進行encode.
class StringTree{var $Value;var $Child;function __construct($name = "StringTree"){$this->Value = $name;$this->Child = array();}private function _ToStr(&$str){$str .= addcslashes($this->Value,"{}")."{";foreach($this->Child as &$val){$val->_ToStr($str);}$str .= "}";}function GetDiction($sp){$a = array();$slen = strlen($sp);if($slen==0) return a;$count = count($this->Child);for($i=0;$i<$count;$i++){$v = $this->Child[$i]->Value;$pos = strpos($v,$sp);if($pos==-1){$a[$v] = "";}else{$key = substr($v,0,$pos);$val = substr($v,$pos+$slen);$a[$key] = $val;}}return $a;}//把一個對象表示成字串。function ToStr(){$str = "";$this->_ToStr($str);return $str;}//這個函數取代系統的stripcslashes函數, 因為後者不能挑選去掉那些字元前面的反斜線.private function _stripcslashes($str,$chars){$len = strlen($chars);$patern = array();$rp = array();for($i=0;$i<$len;$i++){$patern[$i] = "/\\\\".$chars[$i]."/";$rp[$i] = $chars[$i];}return preg_replace($patern,$rp,$str);}private function _FromStr(&$str,&$offset,$len){for($i=$offset;$i<$len;$i++){if($str[$i]=='{'&&$str[$i-1]!='\\'){$name = substr($str,$offset,$i-$offset);$name = $this->_stripcslashes($name,"{}");$offset = $i + 1;$cst = $this->AddChild($name);//echo $name."<br/>";$cst->_FromStr($str,$offset,$len);$i = $offset - 1; //執行_FromStr後, offset要麼是"}"的位置 + 1,要麼是$len, 因為for迴圈會自動+1, 這種情況下都需要回退 1 來避免跳過一個字元. }elseif($str[$i]=='}'&&$str[$i-1]!='\\'){$offset = $i + 1;return;}}$offset = $len;}function FromStr($str){$this->Child = array();$this->Value = "";$offset = 0;$len = strlen($str);for($i=$offset;$i<$len;$i++){if($str[$i]=='{'&&($i<=0||$str[$i-1]!='\\')){$name = substr($str,$offset,$i-$offset);$this->Value = stripcslashes($name);$offset = $i + 1;$this->_FromStr($str,$offset,$len);$i = $offset - 1;}elseif($str[$i]=='}'&&($i<=0||$str[$i-1]!='\\')){break;}}}//添加一個子節點, 傳回值是新添加的節點function AddChild($val){$i = count($this->Child);$this->Child[$i] = new StringTree($val);return $this->Child[$i];}//返回子節點的個數function Count(){return count($this->Child);}function Clear(){$this->Child = array();}};/*使用說明: StringTree類有以下函數1. StringTree(root) 建構函式, 參數是這個資料樹的根名稱.2. AddChild(value)添加資料, 參數是一個字串, 是我們需要儲存的資料. 這個函數傳回值也是一個StringTree對象, 這個對象是它上級對象的子物件.3. ToStr()返回代表整個資料樹的字串.4. FromStr(str)從一個字串產生StringTree對象的資料, 這個對象之前的資料會被清空, 這個字串一般就是ToStr()函數返回的字串, 當然也可以自己構造, 構造規則非常簡單.5. Clear()清空這個資料樹的全部子物件資料, 但是根資料不會清空.6. Count()返回這個資料樹的子物件個數.7. GetDiction(sp)返回一個字典數組, 代表當前資料樹對象的子資料, 但是不會包含子資料的下一集子資料. 因為, 實際上每個資料都是一個字串, 所以需要一個sp分隔字元來約定key和value, 比如我們使用AddChild("name:張三"); 這個語句添加了資料, 把sp設定為":", GetDiction函數返回的數組就會有dic["name"]這樣一個元素, 而它的值就是"張三". 如果我添加資料的時候key欄位有重複, 比如AddChild("name:張三");AddChild("name:李四");這樣兩句, 那麼使用GetDiction的時候就只能得到一個資料, 前面的會被覆蓋, 只返回後添加的資料.每一個StringTree對象都有兩個成員變數 Value和Child, 前者就是我們使用AddChild添加的字串值, 所以可以修改這個值, 來達到修改資料的目的. echo AddChild("name:張三")->Value; 輸出將會是"name:張三". Child成員是子StringTree數組, 也就是上級對象的子分支資料.StringTree對象的ToStr()輸出的字串值是如下格式: root{child1{sonchild1{}}child2{}child3{}}, 也就是, 每個資料後面都有一個{}作為分隔, 如果它有子資料, 寫在{}裡面, 並且也要在末尾加上{}. 可以手工構造符合這個規則的字串, 賦值給FromStr來產生StringTree對象樹. 對於錯誤的不符合格式的字串, FromStr可能會部分的解析它, 但是函數不會返回錯誤.雖然使用{}作為分隔字元, 使用AddChild添加的資料, 或者使用Value直接操作字串, 都不用考慮是否含有"{"或"}"符號, ToStr()和FromStr()函數已經做了轉義處理. 但是自己手工構造StringTree資料樹的字串時, 就需要在 "{" 和 "}" 字元前面加"\"來轉義. */$st = new StringTree();$st->AddChild("name:PHPStringTree");$ch2 = $st->AddChild("child:PHPChild2");$st->AddChild("value:PHPString");$ch3 = $ch2->AddChild("AB{C}d");echo $ch3->Value."<br/>";$str = $st->ToStr();echo $str."<br/>";$st = new StringTree();$st->FromStr($str);echo $st->Child[1]->Child[0]->Value."<br/>";$a = $st->GetDiction(":");print_r($a);
輸出:
AB{C}d
StringTree{name:PHPStringTree{}child:PHPChild2{AB\{C\}d{}}value:PHPString{}}
AB{C}d
Array ( [name] => PHPStringTree [child] => PHPChild2 [value] => PHPString )
JavaScript版本:
//和php的同名函數功能相同,str字串裡面如果某個字母包含在chars字串裡, 將會被添加反斜線.function addCSlashes(str, chars) { chars = '([' + chars + '])'; var reg = RegExp(chars, "g"); return str.replace(reg, '\\$1');}//移除指定字元前的反斜線, addCSlashes函數的逆函數.function stripCSlashes(str, chars) { chars = "(\\\\)([" + chars + "])"; var reg = RegExp(chars, "g"); return str.replace(reg, "$2");}function StringTree(str) { this.Value = str; //.replace(,); this.Child = new Array();//這個函數用於把一個值按分割符sp, 存成字典, 然後可以方便的取出特定的值this.GetDiction = function(sp){var a = new Array();for(var i=0;i<this.Child.length;i++){var v = this.Child[i].Value;var index = v.indexOf(sp);var key,val;if(index==-1){key = v;val = "";}else{key = v.substr(0,index);val = v.substr(index+sp.length);}a[key] = val;}return a;} this.ToStr = function() { var s = new Array(); s.push(addCSlashes(this.Value, "{}")); s.push("{"); for (var i in this.Child) { s.push(this.Child[i].ToStr()); } s.push("}"); return s.join(""); } this.AddChild = function(str) { var st = new StringTree(str); this.Child.push(st); return st; } this._FromStr = function(str, offset, len) { for (var i = offset; i < len; i++) { if (str[i] == '{' && str[i - 1] != '\\') { var name = str.substr(offset, i - offset); name = stripCSlashes(name, "{}"); offset = i + 1; var cst = this.AddChild(name); offset = cst._FromStr(str, offset, len); i = offset - 1; } else if (str[i] == '}' && str[i - 1] != '\\') { offset = i + 1; return offset; } } return len; } this.FromStr = function(str) { this.Value = ""; var offset = 0; var len = str.length; for (var i = offset; i < len; i++) { if (str[i] == '{' && (i <= 0 || str[i - 1] != '\\')) { var name = str.substr(offset, i - offset); this.Value = stripCSlashes(name, "{}"); offset = i + 1; offset = this._FromStr(str, offset, len); i = offset - 1; } else if (str[i] == '}' && (i <= 0 || str[i - 1] != '\\')) { break; } } }}document.write("<br/><br/>JavaScript:<br/>");var st = new StringTree("JavaScriptStringTree");st.AddChild("name:JavaScriptStringTree");var ch2 = st.AddChild("child:JavaScriptChild2");st.AddChild("value:JavaScriptString");ch2.AddChild("ABC");var str = st.ToStr();document.write(str+"<br/>");st = new StringTree();st.FromStr(str);document.write(st.Child[1].Child[0].Value+"<br/>");var dic = st.GetDiction(":");document.write("name:"+dic["name"]+"<br/>");document.write("child:"+dic["child"]+"<br/>");document.write("value:"+dic["value"]+"<br/>");
JavaScript版本的StringTree的函數和成員以及用法和PHP版本完全相同, 包括大小寫, 所以不再重複, 參考PHP版本的說明.