type OpenXmlElement = class public function Create(_node: XmlNode);overload; function Create(_parent: tslobj; _prefix: string; _local_name: string);overload; function Init();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 Elements(): array of tslobj; function Attributes(): array of OpenXmlAttribute; function Xmlns(_prefix: string): string; public function AppendChild(_obj: tslobj); // OpenXmlElement or OpenXmlPcdata function InsertAfter(_obj: tslobj; _pos_obj: tslobj); // function InsertBefore(_pos_obj: tslobj; _obj: tslobj); // function PrependChild(_obj: tslobj); // function RemoveChild(_obj: tslobj); // function SetAttribute(_obj: OpenXmlAttribute); public LocalName: string; // 本地名称 [weakref]Parent: tslobj; // 父类 Prefix: string; // 前缀 XmlNode: XmlNode; // XMLNode节点 ElementName: string; protected attributes_: array of OpenXmlAttribute; // 属性 attributes_pf_: tableArray; // child_elements_: array of tslobj; // 子节点元素 sorted_child_: tableArray; container_: TSOfficeContainer; xmlns_: 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); xmlns_ := array(); 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(); xmlns_ := array(); end; function OpenXmlElement.InitNode(_node: XmlNode);virtual; begin {self.}XmlNode := _node; if not _node then return; tslassigning_backup := tslassigning; tslassigning := 1; node := _node.FirstChild(); while ifObj(node) do begin node_name := node.GetName(); arr := sorted_child_[node_name]; if ifarray(arr) then begin pf := arr[1]; obj := pf.Do(); obj.InitNode(node); end node := node.NextElement(); end tslassigning := tslassigning_backup; end; function OpenXmlElement.GetOrCreateNode(_obj: tslobj); begin if not ifObj({self.}XmlNode) then {self.}XmlNode := {self.}Parent.GetOrCreateNode(self); nearest_node := nil; child_elements := container_.Get(); 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; attrs := {self.}XmlNode.Attributes(); for k, v in attrs do begin pos := pos("xmlns", k); if pos then begin xmlns_[k] := k = "xmlns" ? new OpenXmlAttribute("", "xmlns", v) : new OpenXmlattribute("xmlns", k[pos+6:], v); continue; end pf := attributes_pf_[k]; if ifnil(pf) then continue; pf.Do(v); end child_elements := container_.Get(); for k, v in child_elements do v.Deserialize(); end; function OpenXmlElement.Serialize(); begin // xmlns for k, v in xmlns_ do {self.}GetNode().SetAttribute(v.ElementName, v.Value); // Attributes for k, v in attributes_ do if not ifnil(v.Value) then {self.}GetNode().SetAttribute(v.ElementName, v.Value); // Children child_elements := container_.Get(); for k, v in child_elements do v.Serialize(); end; function OpenXmlElement.Marshal(): tableArray; begin child_elements := container_.Get(); child_arr := array(); for k, v in child_elements do begin 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.Xmlns(_prefix: string): string; begin k := ifnil(_prefix) ? "xmlns" : "xmlns:" + _prefix; if tslassigning then begin if ifnil(xmlns_[k]) then xmlns_[k] := ifnil(_prefix) ? new OpenXmlAttribute("", "xmlns", nil) : new OpenXmlAttribute("xmlns", _prefix, nil); end return xmlns_[k]; end; function OpenXmlElement.Elements(): array of tslobj; begin return container_.Get(); end; function OpenXmlElement.InsertAfter(_obj: tslobj; _pos_obj: tslobj); begin container_.InsertAfter(_obj, _pos_obj); end; function OpenXmlElement.AppendChild(_obj: tslobj); begin container_.Append(_obj); end;