iphonelazext: read XML plist file into the structure

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4033 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
skalogryz
2015-03-15 05:49:27 +00:00
parent 571956ccde
commit 2e169dddfe

View File

@ -22,101 +22,209 @@ uses
Classes, SysUtils, DOM, XMLRead; Classes, SysUtils, DOM, XMLRead;
type type
{ TPListFile } TPlistType = (ltString, ltArray, ltDict, ltData, ltDate, ltBoolean, ltNumber);
TPListFile = class(TObject)
{ TPListValue }
TPListValue = class(TObject)
private private
fFileName : String; fType : TPlistType;
fDoc : TXMLDocument;
firstkey : TDOMNode;
protected
procedure ReadValues;
//todo: add "parent" for FindKeyNode
function FindKeyNode(const keyName: string): TDOMNode;
public public
constructor Create(const AFileName: String); str : WideString;
destructor Destroy; override; binary : array of byte;
function GetStrValue(const Key: String): String; date : TDateTime;
bool : Boolean;
number : Double;
count : Integer;
items : array of TPListValue;
names : array of string;
constructor Create(AType: TPlistType);
function AddValue: Integer;
property ValueType: TPListType read fType;
end; end;
{ TPListFile }
TPListFile = class(TObject)
public
root : TPListValue;
destructor Destroy; override;
end;
function LoadFromXML(const fn: string; plist: TPListFile): Boolean; overload;
function LoadFromXML(doc: TXMLDocument; plist: TPListFile): Boolean; overload;
procedure DebugPlistFile(const fl: TPListFile; Recursive: Boolean = false);
function WriteXML(const plist: TPlistFile): string;
implementation implementation
{ TPListFile } procedure DebugValue(kv: TPListValue; const prefix: string );
var
constructor TPListFile.Create(const AFileName: String); i : integer;
begin begin
fFileName := AFileName; for i:=0 to kv.count-1 do begin
inherited Create; if kv.fType=ltDict then
writeln(prefix,kv.names[i],' (',kv.items[i].ValueType,')');
case kv.items[i].fType of
ltString: writeln(prefix+' ', kv.items[i].str);
ltBoolean: writeln(prefix+' ', kv.items[i].bool);
ltDict: begin
writeln;
DebugValue(kv.items[i],prefix+' ');
end;
ltArray: begin
//writeln;
DebugValue(kv.items[i],prefix+' ');
end;
end;
end;
end;
procedure DebugPlistFile(const fl: TPListFile; Recursive: Boolean = false);
begin
DebugValue(fl.root,'');
end;
const
prefix=
'<?xml version="1.0" encoding="UTF-8"?>'+LineEnding+
'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">'+LineEnding+
'<plist version="1.0">'+LineEnding;
function WriteXML(const plist: TPlistFile): string;
begin
Result:=prefix;
Result:=Result+'</plist>';
end;
function LoadFromXML(const fn: string; plist: TPListFile): Boolean; overload;
var
doc : TXMLDocument;
begin
ReadXMLFile(doc, fn);
Result:=LoadFromXML(doc, plist);
end;
function ReadValByNode(valnode: TDomNode): TPListValue; forward;
function NodeNameToPListType(const nd: string; var pl: TPlistType) : Boolean;
begin
Result:=true;
if nd='string' then pl:=ltString
else if nd ='array' then pl:=ltArray
else if (nd ='fasle') or (nd = 'true') then pl:=ltBoolean
else if (nd = 'dict') then pl:=ltDict
//TPlistType = (ltData, ltDate, ltNumber);
else Result:=false;
end;
procedure ReadArrVal(parent: TDomNode; kv: TPListValue);
var
idx : Integer;
nd : TDomNode;
begin
if not Assigned(parent) then Exit;
nd:=parent.FirstChild;
while Assigned(nd) do begin
idx:=kv.AddValue;
kv.items[idx]:=ReadValByNode(nd);
nd:=nd.NextSibling;
end;
end;
procedure ReadKeyVal(parent: TDomNode; kv: TPListValue);
var
nd : TDOMNode;
idx : integer;
begin
if not Assigned(parent) then Exit;
nd:=parent.FirstChild;
while Assigned(nd) do begin
if nd.NodeName='key' then begin
idx:=kv.AddValue;
kv.names[idx]:=nd.TextContent;
nd:=nd.NextSibling;
if Assigned(nd) then begin
kv.items[idx]:=ReadValByNode(nd);
nd:=nd.NextSibling;
end;
end else
nd:=nd.NextSibling;
end;
end;
function ReadValByNode(valnode: TDomNode): TPListValue;
var
t : string;
tp : TPlistType;
begin
Result:=nil;
if not Assigned(valnode) then Exit;
if not NodeNameToPListType(valnode.NodeName, tp) then Exit;
Result:=TPListValue.Create(tp);
case tp of
ltBoolean: Result.bool:=(valnode.NodeName='true'); // false is false
ltString: Result.str:=valnode.TextContent;
ltArray: ReadArrVal(valnode, Result);
ltDict: ReadKeyVal(valnode, Result);
end;
end;
function LoadFromXML(doc: TXMLDocument; plist: TPListFile): Boolean; overload;
var
root : TDOMNode;
nd : TDOMNode;
begin
Result:=false;
root:=doc.FirstChild; //('plist');
if not Assigned(root) then Exit;
while Assigned(root) do begin
if (root.NodeType = ELEMENT_NODE) and (root.NodeName = 'plist') then
Break;
root:=root.NextSibling;
end;
if not Assigned(root) then Exit;
nd:=root.FirstChild;
plist.root:=ReadValByNode(nd);
Result:=true;
end; end;
destructor TPListFile.Destroy; destructor TPListFile.Destroy;
begin begin
fDOC.Free; root.Free;
inherited Destroy; inherited Destroy;
end; end;
function TPListFile.GetStrValue(const Key: String): String; { TPListValue }
var
node : TDOMNode;
begin
Result:='';
node:=FindKeyNode(Key);
if not Assigned(node) then Exit;
node:=node.NextSibling; constructor TPListValue.Create(AType: TPlistType);
if Assigned(node) and (node.NodeName='string') then begin
Result:=node.TextContent inherited Create;
else fType:=AType;
Result:='';
end; end;
procedure TPListFile.ReadValues; function TPListValue.AddValue: Integer;
var
plist : TDOMNode;
begin begin
firstkey:=nil; if not (fType in [ltArray, ltDict]) then begin
try Result:=0;
ReadXMLFile(fDoc, fFileName);
except
end;
if not Assigned(fDoc) then begin
fDoc:=TXMLDocument.Create;
Exit; // create an empty document
end;
try
plist:=fDoc.FindNode('plist');
if not Assigned(plist) then Exit;
while Assigned(plist) do begin
if (plist is TDOMElement) and (plist.NodeName='plist') and (plist.ChildNodes.Count>0) then
Break;
plist:=plist.NextSibling;
end;
firstkey:=plist.FindNode('dict');
if Assigned(firstkey) then
firstkey:=firstkey.FindNode('key');
except
firstkey:=nil;
end;
end;
function TPListFile.FindKeyNode(const keyName: string): TDOMNode;
begin
if not Assigned(fDoc) then ReadValues;
if not Assigned(firstkey) then begin
Result:=nil;
Exit; Exit;
end; end;
Result:=firstkey; Result:=count;
while Assigned(Result) do begin if count=length(items) then begin
if (Result.NodeName='key') and (Result.TextContent=keyName) then Exit; if count=0 then SetLength(items, 4)
Result:=Result.NextSibling; else SetLength(items, length(items)*2);
if fType=ltDict then SetLength(names, length(items));
end; end;
inc(count);
end; end;
end. end.