OfficeXml/openxml/OpenXmlElement.tsf

237 lines
7.4 KiB
Plaintext

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;