Поиск по блогу

понедельник, 8 декабря 2008 г.

Отображение XML в виде дерева (TreeView): Delphi

Во многих программах конфиги хранятся в файлах формата XML. Встала задача — отобразить XML в виде дерева.

Создаем форму, на которой обязательно должны присутствовать кнопка открытия файла (и OpenDialog, соответственно) и TreeView. Остальное — опционально.
delphi xml editor

Подключаем библиотеки XmlDoc, XMLIntf (про XMLIntf, возможно, напишу отдельным постом).

Объявляем класс TNodeRec.

type
TNodeRec = class
TreeNode : TTreeNode;
XMLNode : iXMLNode;
end;


Переменные:

var
XDoc : TXMLDocument;
FName : String;
bkpXml : String;
CurrNode,
ClipboardNode : iXMLNode;


Функции:


function GetPathByNodeIdx (T : TTreeNode) : TStringList;
begin
Result:= TStringList.Create;
if T=nil then exit;
while T.Parent<>nil do
begin
Result.Insert(0,IntToStr(integer(T.Data)));
T:=T.Parent;
end;
Result.Insert(0,IntToStr(integer(T.Data)));
end;

function SetXmlPosByPathIdx (aSL: TStringList; aXmlDocument : TXMLDocument) : IXMLNode;
var
i : integer;
iNODE : IXMLNode;
begin
iNode:=nil;
if aSL.Count=0 then exit;
try
iNODE:=XDoc.ChildNodes.Nodes [StrToInt(aSL[0])];
for i:=1 to aSL.Count -1 do
iNode:=iNODE.ChildNodes[StrToInt(aSL[i])];
Result:=iNODE;
except
end;
end;


На OnCreate формы вешаем:


procedure TfrmMain.FormCreate(Sender: TObject);
begin
XDocNodesList:=TList.Create;
XDoc:=TXMLDocument.Create(Self);
XDoc.Active:=true;
OpenDialog.InitialDir:=ExtractFilePath(ParamStr(0));
end;


На OnDestroy:
procedure TfrmMain.FormDestroy(Sender: TObject);
begin
ClearNodeList;
XDocNodesList.Free;
XDoc.Free;
end;


Обработчик нажатия на кнопку "Загрузить XML":
procedure TfrmMain.acLoadExecute(Sender: TObject);
var
i : integer;
tmpNode : IXMLNode;
begin
if OpenDialog.Execute then
begin
FName:=OpenDialog.FileName;
SaveDialog.FileName:=FName;
XDoc.LoadFromFile(FName);

for i:=0 to XDoc.ChildNodes.Count - 1 do
begin
tmpNode:=XDoc.ChildNodes[i];
TreeView.Items.AddChildObject(TreeView.TopItem,tmpNode.NodeName,
pointer(i));
if tmpNode.HasChildNodes then TreeView.TopItem.HasChildren:=true;
end;
end;
acRefresh.Execute;
bkpXml:=XDoc.XML.Text;
end;


После этого мы уже можем в первый раз опробовать работу программы: в TreeView загрузится XML, но нам будет видно только рутовую вершину (как на 1-ом рисунке). Чтобы можно было разворачивать узлы и просматривать их текст и атрибуты — надо написать еще несколько обработчиков.

procedure TfrmMain.acRefreshExecute(Sender: TObject);
var
i : integer;
tmpNode : IXMLNode;
begin
RebuildTree;
acRefreshMemBody.execute;
end;

procedure TfrmMain.RebuildTree;
var
i : integer;
XNodeItem : iXmlNode;
PNodeItem,
SelectedTrNode,
TrNodeItem,
TrNodeChild : TTreeNode;
NodeRec,
ChildNodeRec : TNodeRec;
Index : integer;
SL : TStringList;
begin
SL:=GetPathByNodeIdx (TreeView.Selected);
CurrNode:=SetXmlPosByPathIdx (SL, XDoc);
SL.Free;

Index :=0;
TreeView.Items.Clear;
ClearNodeList;
NodeRec:=TNodeRec.Create;
TrNodeItem:=TreeView.TopItem;
NodeRec.TreeNode:=TrNodeItem;
XNodeItem:=XDoc.Node;
NodeRec.XMLNode:=XNodeItem;
XDocNodesList.Add(NodeRec);

while XDocNodesList.Count > Index do
begin
NodeRec:=TNodeRec(XDocNodesList[Index]);
XNodeItem:=NodeRec.XMLNode;
TrNodeItem:=NodeRec.TreeNode;
if XNodeItem=CurrNode then SelectedTrNode:=TrNodeItem;
for i:=0 to XNodeItem.ChildNodes.Count -1 do
begin
if XNodeItem.ChildNodes[i].NodeName<>'#text' then
TrNodeChild:=
TreeView.Items.AddChildObject(
TrNodeItem,
XNodeItem.ChildNodes[i].NodeName,
pointer(i));

ChildNodeRec:=TNodeRec.Create;
ChildNodeRec.TreeNode:=TrNodeChild;
ChildNodeRec.XMLNode:=XNodeItem.ChildNodes[i];
XDocNodesList.Add(ChildNodeRec);
end;
inc(Index);
end;

if SelectedTrNode<>nil then SelectedTrNode.Selected:=true;
TreeView.Select(SelectedTrNode,[]);
end;


Сейчас при перемещении по узлам уже наблюдаем более-менее приемлемый результат:

xml editor delphi

редактирование XML (Delphi)

Дальше остается решить вопросы редактирования и добавления узлов и атрибутов.) Это будет домашним заданием.
___

Редакция от 13.01.2010
Продолжение цикла статей:
Добавление и удаление узлов (вершин) в XML в Delphi (с использованием компонента TTreeView). Там же вы найдете ссылку для скачивания исходников.

Статьи схожей тематики:



13 комментариев:

  1. Прикольная статья ... а можна исходники ?

    ОтветитьУдалить
  2. Ну тут и так все листинги приведены... Исходников у меня сейчас под рукой нет.

    ОтветитьУдалить
  3. Листинги то приведены, но что то не получается сделать самому %)
    Буду очень благодарен если все же найдете исходники ...

    ОтветитьУдалить
  4. Masha, очень нужна эта программа ... дайте плиз исходники, а то самому неполучается сделать %)

    ОтветитьУдалить
  5. Masha, как с вами связаться ?

    ОтветитьУдалить
  6. BOSS, связаться со мной можно по емейлу в профайле. Но если вы хотите связаться затем, чтобы получить исходники, - я вам ничем помочь не могу, их у меня на этой машине нет. Когда писала статью - делала программу, все работало, так что приведенные тут листинги - полностью рабочие и опробованные. А если у вас не получается по готовым листингам все восстановить - хм, тут уж я точно помочь не могу :) Заново делать форму и копировать все в проект у меня нет ни времени, ни желания, извините...)

    ОтветитьУдалить
  7. Masha выручайте в универе завал ... Дерево в тривью построил, а от отобразить атрибути и текст среди тегов не могу (так как у вас в последнем скриншоте).

    Помогите! буду очень благодарен !

    ОтветитьУдалить
  8. Как же весело вызывать процедуры - acRefreshMemBody которых нет в статье!

    ОтветитьУдалить
  9. Нда, кто нибудь пробывал по этим исходникам программу сделать? Да тут половины переменных нет!

    ОтветитьУдалить
  10. Это дерево - не 'дуб' :)
    Переменных нет - создайте сами, функции обработки интерфейса сами допишете как вам нужно, может ей ещё листинг из System-а сюда?

    ОтветитьУдалить
  11. Обращение к тем, кто решит оставить комментарий типа "нет половины кода", "ничего не пашет" и т.д. (регулярно отклоняю такие комментарии, так как прежде чем комментировать - надо как минимум внимательно прочитать). В конце статьи есть ссылка, по которой вы можете перейти на другую статью, в которой разжевано абсолютно все и кроме всего прочего приложены исходники. Пожалуйста, хотя бы уважайте чужой труд. И уж если у вас нет ума и терпения, чтобы по подсказкам добраться до верного решения, то обойдитесь без написания комментария.

    С уважением.

    ОтветитьУдалить
  12. выдаёт ошибку
    [dcc32 Error] Unit6.pas(93): E2003 Undeclared identifier: 'acRefresh'
    и ещё такую
    [dcc32 Error] Unit6.pas(108): E2003 Undeclared identifier: 'ClearNodeList'

    Если эти строки закоментировать тогда потом выдаёт такую ошибку при выборе файла
    Line: 1
    <!DOCTYPE html PUBLIC "-//WAPFORUM//DTD

    ОтветитьУдалить
  13. Откуда вы берете все эти библиотеке сами что-ли пишите XmlDoc, XMLIntf потому, что пытался скачать в интернете о них и слова нет?

    ОтветитьУдалить

Комментарии модерируются, вопросы не по теме удаляются, троллинг тоже.

К сожалению, у меня нет столько свободного времени, чтобы отвечать на все частные вопросы, так что, может, свой вопрос лучше задать на каком-нибудь форуме?

Поделиться