Type NodeInfo = class

public
	Function Create(parentObj, name);
	Begin
		if ifObj(parentObj) then
			NodeUri := parentObj.NodeUri = '' ? name : (parentObj.NodeUri + '/' + name);
		else
			NodeUri := '';
		NodeName := name;
		ExtAttr  := array();
		ExtNodes := array();
		ReplaceArr := array();
	End

	Function Root(); virtual;
	Begin
		return RootObj;
	End

	Function Update(position);overload;
	Begin
		if ifObj(RootObj) then Begin
			arr := Marshal();
			if length(arr['attributes']) or length(arr['children']) then Begin
				curNode := class(TSXml).GetNode(RootObj, NodeUri, position);
				if ifObj(curNode) then
					class(TSXml).UpdateNode(curNode, arr['attributes'], arr['children']);
			End;
		End;
	End;

	Function Update();overload;
	Begin
		self.Update("end");
	End;

	Function Delete();overload;
	Begin
		if ifObj(RootObj) then
		begin
			curNode := class(TSXml).GetNode(RootObj, NodeUri);
			if ifObj(curNode) then curNode.DeleteChildren();
		end
	End;

	Function Delete(name);overload;
	Begin
		if not ifObj(RootObj) then return false;
		node := NodeUri <> '' ? class(TSXml).GetNode(RootObj, NodeUri) : RootObj;

		attrs := GetAttrsEx();
		lName := lowerCase(name);
		r := sselect * from attrs where lName = lowerCase([0]) end;
		if istable(r) then
		begin
			node.DeleteAttribute(r[1]);
			return true;
		end

		children := GetChildren();
		r := select * from children where lName = lowerCase(['field']) end;
		if istable(r) then Begin
			r := r[0];
			delete_node := node.FirstChildElement(r['name']);
			if ifObj(delete_node) then
			begin
				node.DeleteChild(delete_node);
				return true;
			end
		End;
		return false;
	End;

	Function GetAttrs(); virtual;
	Begin
		return ExtAttr;
	End

	Function GetChildren(); virtual;
	Begin
		return ExtNodes;
	End

	Function GetNode(index);  // 返回的index的对象
	Begin
		return ExtNodes[index]['obj'];
	End

	Function GetCount();	 // 返回当前节点的个数
	Begin
		return length(ExtAttr);
	End

	// arr := array(('Size', 'sz', 15), ('Style', 'style', 'line'));
	Function AddAttr(arr);	   // 添加属性
	Begin
		if not istable(arr) then return;
		ExtAttr union= arr;
		return 1;
	End

	Function Marshal();
	Begin
		children_ := nil;
		GetChildrenEx();	//优化为变量，减少数据COPY，2022-12-10
		child_arr := array();
		name_map := array();
		len := 0;
		for i:=0 to length(children_)-1 do
		begin
			node_type := children_[i]['nodeType'];
			obj := children_[i]['obj'];
			if ifnil(obj) then continue;
			if not ifObj(obj) and not ifnil(name_map[children_[i]['name']]) and children_[i]['attrEx'] <> '' then
			begin
				child_arr[name_map[children_[i]['name']]]['attributes'] union=array(children_[i]['attrEx'] : obj);
				continue;
			end

			arr := array('type': 'element', 'name': children_[i]['name'], 'attributes': array());
			if node_type = 'empty' then  // <b/>
			begin
				empty_name := children_[i]['attrEx'] ? children_[i]['attrEx'] : 'val';
				if obj = 0 then arr['attributes'] := array(empty_name: 0);
				else if obj = 1 then arr['attributes'] := array(empty_name: 1)
			end
			else if node_type = 'pcdata' then
			begin
				arr['children'] := array(('type': 'pcdata', 'value': obj));
			end
			else if ifObj(obj) then
			begin
				marshal := obj.Marshal();
				if length(marshal['children'])=0 and length(marshal['attributes'])=0 then continue;
				arr['children'] := marshal['children'];
				arr['attributes'] union= marshal['attributes'];
			end
			else
			begin
				key := children_[i]['attrName'] ? children_[i]['attrName'] : children_[i]['attrEx'] ? children_[i]['attrEx'] : 'val';
				arr['attributes'] := array(key : obj);
			end
			name_map[children_[i]['name']] := len;
			child_arr[len++] := arr;
		end

		name_arr := str2array(NodeName, '/');
		tmp_arr := array('type': 'element', 'name': name_arr[length(name_arr)-1], 'children': child_arr);
		for i:=length(name_arr)-2 downto 0 do
		begin
			tmp_arr := array('type': 'element', 'name': name_arr[i], 'children': array(tmp_arr));
		end

		attrs_arr := GetAttrs();
		tmp_arr['attributes'] := array();
		for i:=0 to length(attrs_arr)-1 do
		begin
			if not ifnil(attrs_arr[i, 2]) then Begin
				tmp_arr['attributes'][ attrs_arr[i, 1] ] := attrs_arr[i, 2];
			End;
		end
		return tmp_arr;
	End

	Function NewChildNode(nodeArr);
	Begin
		if not ifarray(nodeArr) then return 0;
		if not ifstring(nodeArr['name']) then return 0;
		arr := array((
			'name': nodeArr['name'],
			'obj': nodeArr['obj'],
			'attrEx': nodeArr['attrEx'],
			'nodeType': nodeArr['nodeType'],
		));
		ExtNodes union= arr;
		return 1;
	End

	Function Value(name, nottransferable);
	Begin
		if not ifObj(RootObj) then return nil;
		if NodeUri <> '' then
			node := class(TSXml).GetNode(RootObj, NodeUri);
		else
			node := RootObj;
		if not ifObj(node) then return nil;

		attrs := GetAttrsEx();
		lName := lowerCase(name);
		r := sselect * from attrs where lName = lowerCase([0]) end;
		if istable(r) then
		begin
			value := node.GetAttribute(r[1]);
			return nottransferable ? value : trystrtofloat(value, r) ? r : value;
		end

		children := GetChildren();
		r := select * from children where lName = lowerCase(['field']) end;
		if istable(r) then Begin
			r := r[0];
			node := node.FirstChildElement(r['name']);
			if not ifObj(node) and r['nodeType'] = 'empty' and not nottransferable then return false;
			if not ifObj(node) then return nil;
			if r['nodeType'] = 'pcdata' then //返回文本串
				return node.GetText();
			if ifObj(r['obj']) then	//对象，返回XML串
				return node.Data();
			key := r['attrName'] ? r['attrName'] : r['attrEx'] ? r['attrEx'] : 'val';
			value := node.GetAttribute(key);
			if r['nodeType'] = 'empty' and value = '' then return true;
			return nottransferable ? value : trystrtofloat(value, r) ? r : value;
		End;
		return nil;
	End;

	Function Replace(hash, bChild);
	Begin
		if istable(hash) then Begin
			ReplaceArr := hash;
			replaceNodeName();
			if bChild then Begin
				r := GetChildren();
				for i:=0 to length(r)-1 do Begin
					if ifObj(r[i]['obj']) then
						r[i]['obj'].Replace(hash, bChild);
				End;
			End;
		End;
	End

	Function GetChildrenEx();
	Begin
		if not ifarray(children_) then Begin
			children_ := getChildren();
			if not istable(ReplaceArr) then Begin
				for i:=0 to length(children_)-1 do Begin
					if ifarray(children_[i]['obj']) then Begin
						if istable(children_[i]['obj']) then
							hasArr := 1;
						else
							children_[i]['obj'] := nil;
					End;
				End;
			End;
			if hasArr or istable(ReplaceArr) then Begin
				a := array();
				for i:=0 to length(children_)-1 do Begin
					if istable(ReplaceArr) then
						children_[i]['name'] := ReplaceName(children_[i]['name']);
					if istable(children_[i]['obj']) then Begin
						a union= children_[i]['obj'];
					End
					else
						a[ length(a) ] := children_[i];
				end;
				children_ := a;
			End;
		End;
	End;

	Function GetAttrsEx();
	Begin
		return GetAttrs();//暂时没有发现需要更新属性前缀的情况
		if not istable(ReplaceArr) then return GetAttrs();
		attr := GetAttrs();
		for i:=0 to length(attr)-1 do
			attr[i][1] := ReplaceName(attr[i][1]);
		return attr;
	End

private
	Function replaceNodeName();
	Begin
		for k, v in ReplaceArr do
		begin
			NodeName := ReplaceStr(NodeName, k, v);
		end
	End

	Function ReplaceName(name);
	Begin
		for k,v in ReplaceArr do Begin
			if k='' then
				name := v + name;
			else
				name := ReplaceStr(name, k, v);
		End;
		return name;
	End;
public
	NodeName;
	ExtAttr;
	ExtNodes;
	ReplaceArr;
	RootObj; 		// xml node
	NodeUri:string;
	children_;
End
