237 lines
7.3 KiB
Plaintext
237 lines
7.3 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_: tableArray; // 属性
|
|
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;
|