type OpenXmlElement = class public function Create(_node: XmlNode);overload; function Create(_parent: tslobj; _prefix: string; _local_name: string);overload; function Init();virtual; function InitAttributes();virtual; function InitChildren();virtual; function InitNode(_node: XmlNode);virtual; function Copy(_obj: tslobj);virtual; function Deserialize(); function Serialize(); function Marshal(): tableArray; function GetOrCreateNode(_obj: tslobj); function GetNode(): XmlNode; // 增删改查接口 function Append(_obj: tslobj): boolean; // OpenXmlElement or OpenXmlPcdata function InsertAfter(_pos_obj: tslobj; _obj: tslobj): boolean; function InsertBefore(_pos_obj: tslobj; _obj: tslobj): boolean; function Prepend(var _obj: tslobj): boolean; function Remove(_obj: tslobj): boolean; function AddAttribute(_obj: OpenXmlAttribute): boolean; function Elements(): array of tslobj; protected function IsValidChild(_obj: tslobj); function FindChild(_obj: tslobj); function InsertChild(_obj: tslobj; _pos: integer); public LocalName: string; // 本地名称 [weakref]Parent: tslobj; // 父类 Prefix: string; // 前缀 XmlNode: XmlNode; // XMLNode节点 ElementName: string; protected attributes_: array of OpenXmlAttribute; // 属性 child_elements_: array of tslobj; // 子节点元素 sorted_child_: tableArray; end; function OpenXmlElement.Create(_node: XmlNode);overload; begin node_name := _node.GetName(); pos := Pos(":", node_name); if pos then {self.}Create(nil, node_name[:pos-1], node_name[pos+1:]); else {self.}Create(nil, nil, node_name); {self.}InitNode(_node); end; function OpenXmlElement.Create(_parent: tslobj; _prefix: string; _local_name: string);overload; begin {self.}Parent := _parent; {self.}Prefix := _prefix; {self.}LocalName := _local_name; {self.}XmlNode := nil; {self.}ElementName := ifString({self.}Prefix) and {self.}Prefix <> "" ? format("%s:%s", {self.}Prefix, {self.}LocalName) : {self.}LocalName; {self.}Init(); {self.}InitAttributes(); {self.}InitChildren(); end; function OpenXmlElement.GetOrCreateNode(_obj: tslobj); begin if not ifObj({self.}XmlNode) then {self.}XmlNode := {self.}Parent.GetOrCreateNode(self); nearest_node := nil; for k, v in child_elements_ do begin if ifObj(v.XmlNode) then nearest_node := v.XmlNode; if v = _obj then begin if ifObj(v.XmlNode) then return v.XmlNode; if ifnil(nearest_node) then return {self.}XmlNode.InsertFirstChild("element", _obj.ElementName); else return {self.}XmlNode.InsertAfterChild(nearest_node, "element", _obj.ElementName); end end raise "No child."; end; function OpenXmlElement.GetNode(): XmlNode; begin if not ifObj({self.}XmlNode) then {self.}XmlNode := {self.}Parent.GetOrCreateNode(self); return {self.}XmlNode; end; function OpenXmlElement.Deserialize(); begin if not ifObj({self.}XmlNode) then return nil; for k, v in attributes_ do begin attr := {self.}XmlNode.GetAttribute(v.ElementName); v.Value := attr = "" ? nil : attr; end for k, v in child_elements_ do v.Deserialize(); end; function OpenXmlElement.Serialize(); begin // Attributes for k, v in attributes_ do if not ifnil(v.Value) then {self.}GetNode().SetAttribute(v.ElementName, v.Value); // Children for k, v in child_elements_ do if ifObj(v) then v.Serialize(); end; function OpenXmlElement.Marshal(): tableArray; begin child_arr := array(); for k, v in child_elements_ do begin if ifnil(v) then continue; arr := array("type": "element", "name": v.ElementName, "attributes": array()); if v is Class(OpenXmlPcdata) or v is Class(OpenXmlElement) then begin marshal := v.Marshal(); if length(marshal["children"]) = 0 and length(marshal["attributes"]) = 0 then continue; arr["children"] := marshal["children"]; arr["attributes"] union= marshal["attributes"]; child_arr[length(child_arr)] := arr; end else if v is Class(OpenXmlEmpty) then begin marshal := v.Marshal(); if length(marshal) > 0 then child_arr[length(child_arr)] := arr; end else begin echo "error = marshal,\n"; end end tmp_arr := array("type": "element", "name": {self.}ElementName, "children": child_arr, "attributes": array()); for k,v in attributes_ do begin if not ifnil(v.Value) then tmp_arr["attributes"][v.ElementName] := v.Value; end return tmp_arr; end; function OpenXmlElement.Append(_obj: tslobj): boolean; // OpenXmlElement or OpenXmlPcdata begin if not {self.}IsValidChild(_obj) then return false; _obj.Parent := self; child_elements_[length(child_elements_)] := _obj; // _obj := nil; return true; end; function OpenXmlElement.InsertAfter(_pos_obj: tslobj; _obj: tslobj): boolean; begin if not {self.}IsValidChild(_pos_obj) or not {self.}IsValidChild(_obj) then return false; find_pos := {self.}FindChild(_pos_obj); if find_pos = -1 then return false; {self.}InsertChild(_obj, find_pos); return true; end; function OpenXmlElement.InsertBefore(_pos_obj: tslobj; _obj: tslobj): boolean; begin if not {self.}IsValidChild(_pos_obj) or not {self.}IsValidChild(_obj) then return false; find_pos := {self.}FindChild(_pos_obj); if find_pos = -1 then return false; {self.}InsertChild(_obj, find_pos-1); return true; end; function OpenXmlElement.Prepend(_obj: tslobj): boolean; begin if not {self.}IsValidChild(_pos_obj) or not {self.}IsValidChild(_obj) then return false; {self.}InsertChild(_obj, 0); return true; end; function OpenXmlElement.Remove(_obj: tslobj): boolean; begin if ifnil(_obj)then // 删除所有 begin if not ifObj({self.}XmlNode) or not ifObj({self.}Parent) or not ifObj({self.}PartName.XmlNode) then return false; {self.}Parent.XmlNode.DeleteChild({self.}XmlNode); return true; end else if {self.}IsValidChild(_obj) then begin if not ifObj(_obj.XmlNode) or not ifObj({self.}XmlNode) then return false; {self.}XmlNode.DeleteChild(_obj.XmlNode); return true; end else if _obj is Class(OpenXmlAttribute) then begin if not ifObj({self.}XmlNode) then return false; {self.}XmlNode.DeleteAttribute(_obj.ElementName); return false; end end; function OpenXmlElement.AddAttribute(_obj: OpenXmlAttribute): boolean; begin if not _obj is Class(OpenXmlAttribute) then return false; attributes_[length(attributes_)] := _obj; return true; end; function OpenXmlElement.InsertChild(_obj: tslobj; _pos: integer); begin for i:=length(child_elements_)-1 downto _pos do child_elements_[i+1] := child_elements_[i]; _obj.Parent := self; child_elements_[_pos] := _obj; end; function OpenXmlElement.IsValidChild(_obj: tslobj): boolean; begin return _obj is Class(OpenXmlPcdata) or _obj is Class(OpenXmlElement) ? true : false; end; function OpenXmlElement.FindChild(_obj: tslobj); begin not_found := true; for k,v in child_elements_ do begin if v = _obj then begin not_found := false; break; end end return not_found ? -1 : k; end; function OpenXmlElement.Elements(): array of tslobj; begin return child_elements_; end;