使用StringTree PHP远程传输数据

6 篇文章 0 订阅


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版本的说明.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值