С Новым годом! Форум программистов, компьютерный форум, киберфорум
Delphi для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.74/246: Рейтинг темы: голосов - 246, средняя оценка - 4.74
0 / 0 / 0
Регистрация: 15.10.2013
Сообщений: 14
1

Где найти мануал по парсингу XML? Как работать с XML в Delphi (в частности, TXMLDocument)?

15.10.2013, 10:14. Показов 48054. Ответов 13

Author24 — интернет-сервис помощи студентам
Всех приветствую!
Раньше несколько лет работал в Матлабе, но теперь приспичило писать программу на Дельфи. Надо открывать xml-файлы, считывать из них информацию (имена элементов, их количество, значения элементов (<element1>Значение</element1>), атрибутов (как сами названия атрибутов, так и их значения).

Работаю в Embarcadero RAD Stiduo XE3. Там есть компонент TXMLDocument, наверно, известный многим программящим на Delphi. Вроде бы и умеет много. Но проблема в том, что по нему нет понятной документации и описания. Хэлп в RAD Studio - фигня, потому что нормальной информации там нет; только разбросанная по страницам скудная справка по некоторым методам и процедурам (без примеров и нормального описания). Перерыл весь инет. Нашёл только темы на форумах с решением конкретных задач, где надо ещё час разбираться что делает та или иная строка, связанная с обращением к xml-файлу. Сидеть и дедуктивным методом пытаться догадаться, что делает та или иная строка кода, метод, процедура - увольте, слишком долго. Наверняка есть пути проще.

Мне же нужно руководство по основным функциям, процедурам и методам, применяемым при работе с xml. Учебник, мануал, описание. Или хотя бы "xml в Delphi для чайников".
Например, вот тут: http://parsing-and-i.blogspot.... elphi.html есть некоторая информация по работе с xml, о том, как посчитать кол-во дочерних узлов, вытащить значения атрибутов и элементов и т. п. Но этого мало. Это лишь частные примеры, которые могут быть понятны подготовленному человеку. Мне же -новичку - нужна более фундаментальная и понятная информация, описание по пунктам (с самого начала!), по переменным, их типам, методам, процедурам и т. п.. Например:

Для открытия xml-файла используем метод XMLDocument1.LoadFromFile('filemane.xml'), где filename - имя файла.
Переменная nodelist типа IXMLNode служит для хранения списка дочерних элементов. Для определения этого списка служит метод Xmldocument1.DocumentElement (где XMLDocument1 - исследуемый xml-файл).
Для определения количества дочерних узлов применяется метод nodelist.ChildNodes.Count (где nodelist - переменная со списком дочерних элементом).
Чтобы запросить содержимое дочернего элемента 'element1' используется метод XMLDocument1.DocumentElement.ChildNodes['element1'].Text...

и в таком духе дальше по всем применяемым методам, процедурам, типам данных.
Где найти подобные мануалы/описания? Кто может помочь?

Пример xml:
<parent>
<element name="el1" attr1="value">Text1</element>
<element name="el2" attr1="value2">Text2</element>
<element2>Text3</element2>
</parent>

Мне собственно нужно научиться делать следующие операции:
-считывать имя корневого элемента, его атрибуты, содержимое;
-считывать количество (это уже умеем) и имена дочерних элементов ('element', 'element2');
-получать значения атрибутов (el1, el2), имена атрибутов (name, attr1) и содержимого элементов (Text1, Text2, Text3), в том числе когда названия элементов одинаковы;
-менять содержимое элементов, в т. ч. по условию (например, поменять элементу element с именем el2 содержимое Text2 на, скажем, Text5;
-добавлять новые элементы, атрибуты.

Я, конечно, могу написать собственный xml-парсер, который будет всё это делать. Но не хотелось бы изобретать велосипед, когда всё это уже изобретено.

Заранее спасибо за конструктивные советы!
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
15.10.2013, 10:14
Ответы с готовыми решениями:

Как работать с XML в Delphi?
Здравствуйте, помогите пожалуйста разобраться, как работать с XML в Delphi У меня есть XML...

Требуется совет по парсингу XML документов
Есть вот такой код string a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16,...

Как работать в Delphi 7 с сетью. (Где найти документацию)
Всем привет. Я собираюсь написать программу для автоматической установки модов на игры, но понятия...

Выгрузка в XML файл результатов запроса. Создание xml схемы с имеющегося xml файла
Доброго времени суток. Имеется необходимый для загрузки пример XML файла и из него необходимо...

13
13107 / 5888 / 1707
Регистрация: 19.09.2009
Сообщений: 8,808
15.10.2013, 12:41 2
Информацию по XML, HTML, CSS и пр. можно брать здесь:
1. W3Schools: http://www.w3schools.com/
2. DOM: http://www.w3schools.com/dom/default.asp
3. DOM Node: http://www.w3schools.com/dom/dom_node.asp
4. DOM Element: http://www.w3schools.com/dom/dom_element.asp

Кроме этого, в редакторе Delphi можно открыть, например, модуль XMLIntf. Там имеются описания интерфейсов:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
...
 
{ IXMLNode }
 
  IXMLNode = interface
    ['{395950C0-7E5D-11D4-83DA-00C04F60B2DD}']
    { Property Accessors }
    function GetAttribute(const AttrName: DOMString): OleVariant;
    function GetAttributeNodes: IXMLNodeList;
    function GetChildNodes: IXMLNodeList;
    function GetChildValue(const IndexOrName: OleVariant): OleVariant;
    function GetCollection: IXMLNodeCollection;
    function GetDOMNode: IDOMNode;
    function GetHasChildNodes: Boolean;
    function GetIsTextElement: Boolean;
    function GetLocalName: DOMString;
    function GetNamespaceURI: DOMString;
    function GetNodeName: DOMString;
    function GetNodeType: TNodeType;
    function GetNodeValue: OleVariant;
    function GetOwnerDocument: IXMLDocument;
    function GetParentNode: IXMLNode;
    function GetPrefix: DOMString;
    function GetReadOnly: Boolean;
    function GetText: DOMString;
    function GetXML: DOMString;
    procedure SetAttribute(const AttrName: DOMString; const Value: OleVariant);
    procedure SetChildValue(const IndexOrName: OleVariant; const Value: OleVariant);
    procedure SetNodeValue(const Value: OleVariant);
    procedure SetReadOnly(const Value: Boolean);
    procedure SetText(const Value: DOMString);
    { Methods }
    function AddChild(const TagName: DOMString; Index: Integer = -1): IXMLNode; overload;
    function AddChild(const TagName, NamespaceURI: DOMString;
      GenPrefix: Boolean = False; Index: Integer = -1): IXMLNode; overload;
    function CloneNode(Deep: Boolean): IXMLNode;
    procedure DeclareNamespace(const Prefix, URI: DOMString);
    function FindNamespaceURI(const TagOrPrefix: DOMString): DOMString;
    function FindNamespaceDecl(const NamespaceURI: DOMString): IXMLNode;
    function GetAttributeNS(const AttrName, NamespaceURI: DOMString): OleVariant;
    function HasAttribute(const Name: DOMString): Boolean; overload;
    function HasAttribute(const Name, NamespaceURI: DOMString): Boolean; overload;
    function NextSibling: IXMLNode;
    procedure Normalize; 
    function PreviousSibling: IXMLNode;
    procedure Resync;
    procedure SetAttributeNS(const AttrName, NamespaceURI: DOMString; const Value: OleVariant);
    procedure TransformNode(const stylesheet: IXMLNode; var output: WideString); overload;
    procedure TransformNode(const stylesheet: IXMLNode; const output: IXMLDocument); overload;
    { Properties }
    property Attributes[const AttrName: DOMString]: OleVariant read GetAttribute write SetAttribute;
    property AttributeNodes: IXMLNodeList read GetAttributeNodes;
    property ChildNodes: IXMLNodeList read GetChildNodes;
    property ChildValues[const IndexOrName: OleVariant]: OleVariant read GetChildValue write SetChildValue; default;
    property Collection: IXMLNodeCollection read GetCollection;
    property DOMNode: IDOMNode read GetDOMNode;
    property OwnerDocument: IXMLDocument read GetOwnerDocument;
    property HasChildNodes: Boolean read GetHasChildNodes;
    property IsTextElement: Boolean read GetIsTextElement;
    property LocalName: DOMString read GetLocalName;
    property NamespaceURI: DOMString read GetNameSpaceURI;
    property NodeName: DOMstring read GetNodeName;
    property NodeType: TNodeType read GetNodeType;
    property NodeValue: OleVariant read GetNodeValue write SetNodeValue;
    property ParentNode: IXMLNode read GetParentNode;
    property Prefix: DOMString read GetPrefix;
    property ReadOnly: Boolean read GetReadOnly write SetReadOnly;
    property Text: DOMString read GetText write SetText;
    property XML: DOMString read GetXML;
  end;
 
{ IXMLNodeList }
 
  IXMLNodeList = interface
    ['{395950C1-7E5D-11D4-83DA-00C04F60B2DD}']
    { Property Accessors }
    function GetCount: Integer;
    function GetNode(const IndexOrName: OleVariant): IXMLNode;
    function GetUpdateCount: Integer;
    { Methods }
    function Add(const Node: IXMLNode): Integer;
    procedure BeginUpdate;
    procedure Clear;
    function Delete(const Index: Integer): Integer; overload;
    function Delete(const Name: DOMString): Integer; overload;
    function Delete(const Name, NamespaceURI: DOMString): Integer; overload;
    procedure EndUpdate;
    function First: IXMLNode;
    function FindNode(NodeName: DOMString): IXMLNode; overload;
    function FindNode(NodeName, NamespaceURI: DOMString): IXMLNode; overload;
    function FindNode(ChildNodeType: TGuid): IXMLNode; overload;
    function FindSibling(const Node: IXMLNode; Delta: Integer): IXMLNode;
    function Get(Index: Integer): IXMLNode;
    function IndexOf(const Node: IXMLNode): Integer; overload;
    function IndexOf(const Name: DOMString): Integer; overload;
    function IndexOf(const Name, NamespaceURI: DOMString): Integer; overload;
    procedure Insert(Index: Integer; const Node: IXMLNode);
    function Last: IXMLNode;
    function Remove(const Node: IXMLNode): Integer;
    function ReplaceNode(const OldNode, NewNode: IXMLNode): IXMLNode;
    { Properties }
    property Count: Integer read GetCount;
    property Nodes[const IndexOrName: OleVariant]: IXMLNode read GetNode; default;
    property UpdateCount: Integer read GetUpdateCount;
  end;
 
{ IXMLNodeCollection }
 
  IXMLNodeCollection = interface(IXMLNode)
    ['{395950C2-7E5D-11D4-83DA-00C04F60B2DD}']
    { Property Accessors }
    function GetCount: Integer;
    function GetNode(Index: Integer): IXMLNode;
    { Public properties }
    procedure Clear;
    procedure Delete(Index: Integer);
    function Remove(const Node: IXMLNode): Integer;
    property Count: Integer read GetCount;
    property Nodes[Index: Integer]: IXMLNode read GetNode; default;
  end;
 
{ IXMLDocument }
 
  TXMLDocOption = (doNodeAutoCreate, doNodeAutoIndent, doAttrNull,
    doAutoPrefix, doNamespaceDecl, doAutoSave);
  TXMLDocOptions = set of TXMLDocOption;
 
  TParseOption = (poResolveExternals, poValidateOnParse, poPreserveWhiteSpace,
    poAsyncLoad);
  TParseOptions = set of TParseOption;
 
  TXMLEncodingType = (xetUnknown, xetUCS_4BE, xetUCS_4LE, xetUCS_4Order2134,
    xetUCS_4Order3412, xetUTF_16BE, xetUTF_16LE, xetUTF_8, xetUCS_4Like,
    xetUTF_16BELike, xetUTF_16LELike, xetUTF_8Like, xetEBCDICLike);
 
  IXMLDocument = interface(IInterface)
    ['{395950C3-7E5D-11D4-83DA-00C04F60B2DD}']
    { Property Accessors }
    function GetActive: Boolean;
    function GetAsyncLoadState: Integer;
    function GetChildNodes: IXMLNodeList;
    function GetDocumentElement: IXMLNode;
    function GetDocumentNode: IXMLNode;
    function GetDOMDocument: IDOMDocument;
    function GetEncoding: DOMString;
    function GetFileName: DOMString;
    function GetModified: Boolean;
    function GetNodeIndentStr: DOMString;
    function GetOptions: TXMLDocOptions;
    function GetParseOptions: TParseOptions;
    function GetSchemaRef: DOMString;
    function GetStandAlone: DOMString;
    function GetVersion: DOMString;
    function GetXML: TStrings;
    procedure SetActive(const Value: Boolean);
    procedure SetDocumentElement(const Value: IXMLNode);
    procedure SetDOMDocument(const Value: IDOMDocument);
    procedure SetEncoding(const Value: DOMString);
    procedure SetFileName(const Value: DOMString);
    procedure SetNodeIndentStr(const Value: DOMString);
    procedure SetOptions(const Value: TXMLDocOptions);
    procedure SetParseOptions(const Value: TParseOptions);
    procedure SetStandAlone(const Value: DOMString);
    procedure SetVersion(const Value: DOMString);
    procedure SetXML(const Value: TStrings);
    { Methods }
    function AddChild(const TagName: DOMString): IXMLNode; overload;
    function AddChild(const TagName, NamespaceURI: DOMString): IXMLNode; overload;
    function CreateElement(const TagOrData, NamespaceURI: DOMString): IXMLNode;
    function CreateNode(const NameOrData: DOMString;
      NodeType: TNodeType = ntElement; const AddlData: DOMString = ''): IXMLNode;
    function GeneratePrefix(const Node: IXMLNode): DOMString;
    function GetDocBinding(const TagName: DOMString;
      DocNodeClass: TClass; NamespaceURI: DOMString = ''): IXMLNode;
    function IsEmptyDoc: Boolean;
    procedure LoadFromFile(const AFileName: DOMString);
    procedure LoadFromStream(const Stream: TStream; EncodingType:
      TXMLEncodingType = xetUnknown);
    procedure LoadFromXML(const XML: string); overload;
    procedure LoadFromXML(const XML: DOMString); overload;
    procedure Refresh;
    procedure RegisterDocBinding(const TagName: DOMString;
      DocNodeClass: TClass; NamespaceURI: DOMString = '');
    procedure Resync;
    procedure SaveToFile(const AFileName: DOMString);
    procedure SaveToStream(const Stream: TStream);
    procedure SaveToXML(var XML: DOMString); overload;
    procedure SaveToXML(var XML: string); overload;
    procedure SetOnAsyncLoad(const Value: TAsyncEventHandler);
    { Properties }
    property Active: Boolean read GetActive write SetActive;
    property AsyncLoadState: Integer read GetAsyncLoadState;
    property ChildNodes: IXMLNodeList read GetChildNodes;
    property DocumentElement: IXMLNode read GetDocumentElement write SetDocumentElement;
    property DOMDocument: IDOMDocument read GetDOMDocument write SetDOMDocument;
    property Encoding: DOMString read GetEncoding write SetEncoding;
    property FileName: DOMString read GetFileName write SetFileName;
    property Modified: Boolean read GetModified;
    property Node: IXMLNode read GetDocumentNode;
    property NodeIndentStr: DOMString read GetNodeIndentStr write SetNodeIndentStr;
    property Options: TXMLDocOptions read GetOptions write SetOptions;
    property ParseOptions: TParseOptions read GetParseOptions write SetParseOptions;
    property SchemaRef: DOMString read GetSchemaRef;
    property StandAlone: DOMString read GetStandAlone write SetStandAlone;
    property Version: DOMString read GetVersion write SetVersion;
    property XML: TStrings read GetXML write SetXML;
  end;
 
...
Из этих описаний видно, какие есть методы и свойства.

На форуме можно поискать примеры.
Например:
Программа редактирования XML - документа
https://www.cyberforum.ru/delp... ost4903448
Парсинг одинаковых тегов из хмл
XML, как вытащить данные
Запись между определенными тегами XML
XML изменение значения между тегами
И т. д.
3
0 / 0 / 0
Регистрация: 15.10.2013
Сообщений: 14
15.10.2013, 12:52  [ТС] 3
За ссылки спасибо, почитаю. Конкретно с самим XML и DOM в целом понятно. Непонятно как, опираясь на DOM, распарсивать файл в Дельфи.

Указанные темы на форуме видел, читал. Но там скорее решение конкретной задачи без общих сведений. Что ж, буду изучать.

В конце концов, никогда не поздно написать свой парсер - боюсь, будет даже проще
0
13107 / 5888 / 1707
Регистрация: 19.09.2009
Сообщений: 8,808
15.10.2013, 13:10 4
Цитата Сообщение от st_tsourkan Посмотреть сообщение
Непонятно как, опираясь на DOM, распарсивать файл в Дельфи.
Содержимое файла загружается в экземпляр TXMLDocument. XMLDocument представляет данные в виде DOM модели. А DOM модель - это дерево, состоящее из узлов. Каждый узел представлен интерфейсом - например, IXMLNode. Остаётся перебирать эти узлы и извлекать из них нужные сведения. Вот и всё, собственно.
Цитата Сообщение от st_tsourkan Посмотреть сообщение
В конце концов, никогда не поздно написать свой парсер - боюсь, будет даже проще
DOM представление для того и придумано, чтобы упростить задачу разбора документа. А написание полноценного парсера XML - это сложная и трудоёмкая задача.

Добавлено через 5 минут
Цитата Сообщение от st_tsourkan Посмотреть сообщение
Но там скорее решение конкретной задачи без общих сведений. Что ж, буду изучать.
На самом деле знать надо только следующее: DOM - это дерево, состоящее из узлов типа IXMLNode. Каждый узел IXMLNode знает о своём родительском узле и знает о своих дочерних узлах. Таким образом, получив доступ к корневому элементу документа:
Delphi
1
2
3
4
5
var
  Node : IXMLNode;
begin
...
  Node := XMLDocument1.DocumentElement;
можно обойти все узлы дерева DOM и взять из них нужные данные.
0
0 / 0 / 0
Регистрация: 15.10.2013
Сообщений: 14
15.10.2013, 13:19  [ТС] 5
Уже понятнее стало
Сам-то принцип ясен. Я просто пока не знаю, как оформить это синтаксически (проблема именно в синтаксисе!).

Ищу пока понятный мануал, где подробно расписано что делает тот или иной метод (а не тип входных/выходных значений и принадлежность к тому или иному классу, как это описано в хэлпе), какие доступны.

Модуль XMLInf, что вы скинули - почти то, что нужно. Найти бы где-нибудь подробное описание его составляющих (методов, процедур) с примерами (именно применительно к Дельфи, а не в общем виде...)
0
13107 / 5888 / 1707
Регистрация: 19.09.2009
Сообщений: 8,808
15.10.2013, 13:36 6
Цитата Сообщение от st_tsourkan Посмотреть сообщение
Найти бы где-нибудь подробное описание его составляющих (методов, процедур) с примерами (именно применительно к Дельфи, а не в общем виде...)
По IXMLNode и по другим интерфейсам на эту тему - есть прямо в справке Delphi. Правда примеров там нет. Но примеры можно на сайте найти.
Цитата Сообщение от st_tsourkan Посмотреть сообщение
Мне собственно нужно научиться делать следующие операции:
-считывать имя корневого элемента, его атрибуты, содержимое;
-считывать количество (это уже умеем) и имена дочерних элементов ('element', 'element2');
-получать значения атрибутов (el1, el2), имена атрибутов (name, attr1) и содержимого элементов (Text1, Text2, Text3), в том числе когда названия элементов одинаковы;
-менять содержимое элементов, в т. ч. по условию (например, поменять элементу element с именем el2 содержимое Text2 на, скажем, Text5;
-добавлять новые элементы, атрибуты.
Вот из этих задач надо выбрать какую-нибудь и решать. А здесь в теме помогут.
0
0 / 0 / 0
Регистрация: 15.10.2013
Сообщений: 14
15.10.2013, 13:38  [ТС] 7
Не получилось к предыдущему сообщению добавить: я просто недоумеваю, неужели нет в сети нормального пошагового описания работы с XML в Дельфи? Хотя бы на английском. Где всё по пунктам разложено. И не применительно к конкретному примеру, а в общем виде.

У меня в xml есть фрагмент:
XML
1
2
3
4
5
6
7
<node1>
<childnode>Text1</childnode>
<childnode>Text2</childnode>
...
<other_childnode>OtherText</other_childnode>
<childnode>TextN</childnode>
</node1>
Не могу понять, как мне обойти дочерние узлы один за одним, выбрать m-й из них (произвольно) и посчитать, сколько каких узлов имеется в родительском (сколько childnode, сколько other_childnode и т. п.). В примерах кое-где это есть, но пытаться угадать что есть что как бы не хотелось

*чешет репу*

Цитата Сообщение от Mawrat Посмотреть сообщение
По IXMLNode и по другим интерфейсам на эту тему - есть прямо в справке Delphi. Правда примеров там нет. Но примеры можно на сайте найти.
Вот из этих задач надо выбрать какую-нибудь и решать. А здесь в теме помогут.
Окей, тогда я действительно опишу задачу конкретнее и выложу тут. Думаю, так было бы продуктивнее. Просто надо решить все из представленных задач (ожидается работа с большим числом разнотипных хмл-файлов).

Что касается описаний в справке Дельфи - не могу их постичь и осилить. Вроде всё понятно, что там описано, но как применить это на практике - непонятно. Вроде бы и не двоечник, склад ума - технический, а решить эту задачу не получается
0
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
32993 / 21299 / 8180
Регистрация: 22.10.2011
Сообщений: 36,594
Записей в блоге: 8
15.10.2013, 13:43 8
Цитата Сообщение от st_tsourkan Посмотреть сообщение
неужели нет в сети нормального пошагового описания работы с XML в Дельфи?
Отсюда и по ссылкам...

Цитата Сообщение от st_tsourkan Посмотреть сообщение
И не применительно к конкретному примеру, а в общем виде.
Что значит "в общем виде"? Пойди туда, не знаю куда? Работу с XML именно на примерах и надо разбирать, иначе не поймешь ничего...
0
0 / 0 / 0
Регистрация: 15.10.2013
Сообщений: 14
15.10.2013, 13:51  [ТС] 9
Цитата Сообщение от UI Посмотреть сообщение
[
Что значит "в общем виде"? Пойди туда, не знаю куда? Работу с XML именно на примерах и надо разбирать, иначе не поймешь ничего...
Под общим видом я имею в виду саму модель синтаксиса, если можно так выразиться. Например, есть xml-файл вида:

XML
1
2
3
4
<parent>
<child>Text5555</child>
<other_child>Text22222</other_child>
</parent>
Например, при помощи выражения XMLDocument1.DocumentElement.ChildNodes[_node_name_: string].Text можно запросить содержимое элемента _node_name_ (здесь: XMLDOcument1 - исследуемый xml-документ).

Прочитав такую форму записи, я сразу пойму, что чтобы получить содержимое элемента <child> - текст Text5555 - мне надо объявить переменную а как строковую и написать:
a:=XMLDocument1.DocumentElement.ChildNodes['child'];

Т. е. мне нужен шаблон синтаксиса (а подставить нужные входные параметры я уже смогу сам).
Я сегодня чуть позже напишу тут суть задачи на конкретном примере. Заранее благодарен за помощь, потому что сам, боюсь, не справлюсь
0
0 / 0 / 0
Регистрация: 15.10.2013
Сообщений: 14
16.10.2013, 18:09  [ТС] 10
Итак, сформулирую свой вопрос применительно к реальной задаче.
Имеется xml-файл следующего вида:

XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<ltm version="1.0" type="settings" >
<progname>LTM</progname>
 
<templateFiles>
    <assets>fon.png</assets>
    <assets>fon_map.png</assets>
    <assets>start.js</assets>
    <assets>up.jpg</assets>
    <images>
        <pano>
            <tiles>pano_u.jpg</tiles>
            <tiles>pano_d.jpg</tiles>
            <tiles>pano_f.jpg</tiles>
        </pano>
        <tour>
            <tourimages>start.jpg</tourimages>
            <tourimages>tmb.jpg</tourimages>
        </tour>
    </images>
</templateFiles>
<dimensions>
    <tiles type="pc">1910</tiles>
    <tiles type="ipad">768</tiles>
    <tiles side="iphone">512</tiles>
    <tourimages name="start.jpg" edge="long">1024</tourimages>
    <tourimages name="start.jpg" edge="short">768</tourimages>
</dimensions>
 
<hotspot name="hs015_2" style="mappoint" scena="scene017" ath="68.17644363437007" />
<hotspot name="hs015_1" style="mappoint" scena="scene014" rz="4436007"  />          
<data name="onstart" mode="noVoice">Some text</data>
<data name="onerror" mode="noVoice">Some errortext</data>
<data name="onerror" mode="alarm">Other errortext</data>
 
</ltm>
Что имеем в тексте программы (оставлены лишь ключевые строки):
Delphi
1
2
3
4
5
6
7
8
9
10
var
parent, child1: IXMLNode;
 
begin
XMLDocument1.LoadFromFile('f:\filename.xml');
XMLDocument1.Active:=true;
.
.
.
end
Что надо научиться делать:
(заранее извиняюсь, если неверно называю составляющие xml-документа)
1. Получить имя корневого элемента (в нашем случае ltm), а также список его атрибутов (version, type) и их значения ('1.0', 'settings').
2. Получить количество элементов, являющихся дочерними по отношению к корневому. В данном случае их 7: templateFiles, dimensions, hotspot, hotspot, data, data, data. Получить имена элементов (тэгов) (templateFiles, dimensions и т. п.). Получив количество элементов и научившись извлекать их имена, я прогоню цикл от 0 до count-1 и сделаю что мне нужно.
3. Получить количество и список атрибутов требуемого элемента. Например, для элемента hotspot. Правильный ответ будет 4 атрибута. Для первого элемента hotspot это будут name, style, scena, ath. Для второго - то же, только вместо атрибута ath - атрибут rz.
Заметьте, в файле 2 элемента hotspot, с разными атрибутами. Вот как с ними работать (если одноимённых элементов больше 1)?
Я хочу так: получаю список дочерних элементов по отн. к корневому (см. п. 2), прогоняю по ним цикл с for и найду элементы hotspot, у которых параметр name равен требуемому (скажем 'hs015_2' - такой элемент будет заведомо один). Можно ли как-то решить этот вопрос без цикла? То есть, получить значение атрибута scena для элемента hotspot, у которого name="hs015_2"?
4. Проделать вышеописанное по отношению к узлам и элементам, являющимся дочерними по отношению к дочерним. В моём примере - узел <images> (дочерний по отношению к <templateFiles> и родительский по отношению к <pano> и <tiles>.
Если я правильно понимаю, надо как-то передать содержимое узла <images> в переменную типа IXMLNode и делать то же, что и в п.1-3. Так?

5. Надо научиться изменять вышеуказанные параметры (задавать свои).

Вроде пока всё. На данном этапе мне важнее всего синтаксические конструкции.
Например,
a:= XMLDocument1.DocumentElement.ChildNodes['progname'].Text - данное выражение присваивает строковой переменной а содержимое элемента <progname>.
a:= VarToStr(XMLDocument1.DocumentElement.ChildNodes['hotspot'].Attributes['rz']) - данное выражение присваивает переменной а значение атрибута rz элемента hotspot.
(эти 2 выражения я на одном форуме раздобыл, а вот дальше как - не знаю).

Кто владеет этой темой, напишите пожалуйста и другие синтаксические конструкции для решения вышеописанных вопросов (как получить атрибуты, их кол-во, кол-во элементов, их имена и т. п.). Главное сейчас - овладеть синтаксисом, а свой алгоритм я уж реализую потом. Заранее всем огромное спасибо! Сам просто не справлюсь.
0
13107 / 5888 / 1707
Регистрация: 19.09.2009
Сообщений: 8,808
28.10.2013, 18:12 11
Лучший ответ Сообщение было отмечено как решение

Решение

По согласованию в ЛС продолжаем тему.

Сначала про открытие/закрытие XML документа.

1. Загрузка XML содержимого из файла в XMLDocument.
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//Загрузить XML документ из файла.
procedure TForm1.Button1Click(Sender: TObject);
var
  S : AnsiString;
  Ws : WideString;
  Fs : TFileStream;
  Od : TOpenDialog;
begin
  //Диалог выбора файла.
  Od := OpenDialog1; //OpenDialog1 уже должен быть на форме.
  if Od.InitialDir = '' then
    Od.InitialDir := ExtractFilePath( ParamStr(0) );
  if not Od.Execute then Exit;
  if not FileExists(Od.FileName) then begin
    MessageBox(0, 'Файл с заданным именем не найден. Действие отменено.'
      ,'Файл не найден!', MB_OK + MB_ICONWARNING + MB_APPLMODAL);
  end;
 
  //Загрузка содержимого из файла в XMLDocument.
  XMLDocument1.LoadFromFile(Od.FileName);
  {Настраиваем XML документ.
  -[doNodeAutoCreate] - запрет на автоматическое  создание узлов при попытке чтения.
  -[doAutoSave] - запрет на автоматическое сохранение изменений при закрытии документа.
  +[doNodeAutoIndent] - при соохранении в файл автоматическая установка отступов согласно структуре XML.
  +[doAttrNull - чтение несуществующего узла возвращает значение NULL (NULL : Variant).}
  XMLDocument1.Options := XMLDocument1.Options - [doNodeAutoCreate, doAutoSave]
    + [doNodeAutoIndent, doAttrNull];
  //Единица отступа перед тегами при сохранении в файл. У меня не сработало.
  XMLDocument1.NodeIndentStr := '  ';
  XMLDocument1.Active := True; //Включаем разбор DOM модели.
 
  //Загрузка содержимого из файла в Memo.
  Fs := TFileStream.Create(Od.FileName, fmOpenRead + fmShareDenyWrite);
  try
    if XMLDocument1.Encoding = 'UTF-8' then begin
      SetLength(S, Fs.Size);
      Fs.Read(S[1], Fs.Size);
      Memo1.Text := Utf8ToAnsi(S);
    end
    else if XMLDocument1.Encoding = 'UTF-16' then begin
      SetLength(Ws, Fs.Size div 2);
      Fs.Read(Ws[1], Fs.Size);
      Memo1.Text := WideCharLenToString(PWideChar(Ws), Length(Ws));
    end else begin
      SetLength(S, Fs.Size);
      Fs.Read(S[1], Fs.Size);
      Memo1.Text := S;
    end;
  finally
    FreeAndNil(Fs);
  end;
end;
2. Запись XML кода из XMLDocument в файл.
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Запись XML кода из XMLDocument в файл.
procedure TForm1.Button2Click(Sender: TObject);
var
  Sd : TSaveDialog;
  Res : Integer;
begin
  //Диалог записи в файл.
  Sd := SaveDialog1; //SaveDialog1 уже должен быть на форме.
  if Sd.InitialDir = '' then
    Sd.InitialDir := ExtractFilePath( ParamStr(0) );
  if not Sd.Execute then Exit;
  if FileExists(Sd.FileName) then begin
    Res := MessageBox(0, 'Файл с заданным именем уже существует. Перезаписать?'
      ,'Перезаписать?', MB_YESNO + MB_ICONQUESTION + MB_APPLMODAL);
    if Res <> IDYES then
      Exit;
  end;
 
  //Загрузка содержимого из файла в XMLDocument.
  XMLDocument1.SaveToFile(Sd.FileName);
end;
Цитата Сообщение от st_tsourkan Посмотреть сообщение
1. Получить имя корневого элемента (в нашем случае ltm), а также список его атрибутов (version, type) и их значения ('1.0', 'settings').
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//Получить сведения о корневом элементе и о его атрибутах.
procedure TForm1.Button3Click(Sender: TObject);
var
  INode : IXMLNode;
  i : Integer;
begin
  if XMLDocument1.IsEmptyDoc then begin
    ShowMessage('Документ пуст. Действие отменено.');
    Exit;
  end;
 
  INode := XMLDocument1.DocumentElement;
  Memo2.Lines.Add('------------------------------');
  Memo2.Lines.Add('Корневой элемент, тег: ' + INode.NodeName);
  Memo2.Lines.Add('Атрибуты:');
  for i := 0 to INode.AttributeNodes.Count - 1 do
    Memo2.Lines.Add(INode.AttributeNodes[i].NodeName
      + '="' + INode.AttributeNodes[i].NodeValue + '"');
  Memo2.Lines.Add('Всего атрибутов: ' + IntToStr(INode.AttributeNodes.Count));
end;
Цитата Сообщение от st_tsourkan Посмотреть сообщение
2. Получить количество элементов, являющихся дочерними по отношению к корневому. В данном случае их 7: templateFiles, dimensions, hotspot, hotspot, data, data, data. Получить имена элементов (тэгов) (templateFiles, dimensions и т. п.). Получив количество элементов и научившись извлекать их имена, я прогоню цикл от 0 до count-1 и сделаю что мне нужно.
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{Получить сведения о тех элементах, которые являются дочерними по отношению к
корневому элементу.}
procedure TForm1.Button4Click(Sender: TObject);
var
  INode : IXMLNode;
  i : Integer;
begin
  if XMLDocument1.IsEmptyDoc then begin
    ShowMessage('Документ пуст. Действие отменено.');
    Exit;
  end;
 
  INode := XMLDocument1.DocumentElement;
  Memo2.Lines.Add('------------------------------');
  Memo2.Lines.Add('Корневой элемент, тег: ' + INode.NodeName);
  Memo2.Lines.Add('Дочерние элементы:');
  for i := 0 to INode.ChildNodes.Count - 1 do
    Memo2.Lines.Add(INode.ChildNodes[i].NodeName);
  Memo2.Lines.Add('Всего дочерних элементов: ' + IntToStr(INode.ChildNodes.Count));
end;
Цитата Сообщение от st_tsourkan Посмотреть сообщение
3. Получить количество и список атрибутов требуемого элемента. Например, для элемента hotspot. Правильный ответ будет 4 атрибута. Для первого элемента hotspot это будут name, style, scena, ath. Для второго - то же, только вместо атрибута ath - атрибут rz.
Атрибуты можно перебрать с помощью коллекции INode.AttributeNodes. Пример кода уже рассматривался выше.
Цитата Сообщение от st_tsourkan Посмотреть сообщение
... Заметьте, в файле 2 элемента hotspot, с разными атрибутами. Вот как с ними работать (если одноимённых элементов больше 1)?
Я хочу так: получаю список дочерних элементов по отн. к корневому (см. п. 2), прогоняю по ним цикл с for и найду элементы hotspot, у которых параметр name равен требуемому (скажем 'hs015_2' - такой элемент будет заведомо один). Можно ли как-то решить этот вопрос без цикла? То есть, получить значение атрибута scena для элемента hotspot, у которого name="hs015_2"?
Да, верно - можно таким образом действовать.
Цитата Сообщение от st_tsourkan Посмотреть сообщение
4. Проделать вышеописанное по отношению к узлам и элементам, являющимся дочерними по отношению к дочерним. В моём примере - узел <images> (дочерний по отношению к <templateFiles> и родительский по отношению к <pano> и <tiles>.
Если я правильно понимаю, надо как-то передать содержимое узла <images> в переменную типа IXMLNode и делать то же, что и в п.1-3. Так?
Выполнить перебор всех узлов в ветви с заданным корнем можно, например, с помощью рекурсивного алгоритма. Или без рекурсии можно использовать стек или очередь.
Пример кода с рекурсивным перебором:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
type
  TArrNodes = array of IXMLNode;
 
//Рекурсивная процедура для перебора элементов с заданным тегом в поддереве с корнем aRoot.
//Корень aRoot - это любой узел XML
procedure EnumNodes(aRoot : IXMLNode; const aTag : String;
  var aArr : TArrNodes; var aCnt : Integer);
const
  Capacity = 10; //Величина приращения длины динамического массива.
var
  INode : IXMLNode;
  i : Integer;
begin
  if VarIsNull(aRoot) then Exit;
 
  for i := 0 to aRoot.ChildNodes.Count - 1 do begin
    INode := aRoot.ChildNodes[i];
    //Если обнаружен элемент с заданным тегом.
    if INode.NodeName = aTag then begin
      //Если требуется, увеличиваем размер массива.
      if Length(aArr) = aCnt then
        SetLength(aArr, aCnt + Capacity);
      //Добавляем элемент в массив.
      aArr[aCnt] := INode;
      Inc(aCnt);
    end;
    //Рекурсивный вызов.
    EnumNodes(INode, aTag, aArr, aCnt);
  end;
end;
 
//Поиск всех элементов с заданным тегом.
procedure TForm1.Button5Click(Sender: TObject);
var
  Arr : TArrNodes;
  INode : IXMLNode;
  Tag : String;
  i, j, Cnt : Integer;
begin
  if XMLDocument1.IsEmptyDoc then begin
    ShowMessage('Документ пуст. Действие отменено.');
    Exit;
  end;
  Tag := InputBox('Поиск элементов с заданным тегом.',
    'Задайте тег:', '');
  if Tag = '' then begin
    MessageBox(Handle, 'Тег не должен быть пустой строкой. Действие отменено.',
      'Отмена', MB_OK + MB_ICONINFORMATION + MB_APPLMODAL);
    Exit;
  end;
 
  {Ищем все элементы с заданным тегом, начиная с корневого элемента.
  Найденные элементы будут записаны в массив Arr.}
  EnumNodes(XMLDocument1.DocumentElement, Tag, Arr, Cnt);
  if Cnt < Length(Arr) then
    SetLength(Arr, Cnt);
  {Перебор найденных элементов и вывод сведений о них.}
  Memo2.Lines.Add('------------------------------');
  Memo2.Lines.Add('Поиск элементов с тегом: ' + Tag);
  for i := 0 to High(Arr) do begin
    INode := Arr[i];
    Memo2.Lines.Add('----------');
    Memo2.Lines.Add('Элемент, тег: ' + INode.NodeName);
    Memo2.Lines.Add('Атрибуты:');
    for j := 0 to INode.AttributeNodes.Count - 1 do
      Memo2.Lines.Add(INode.AttributeNodes[j].NodeName
        + '="' + INode.AttributeNodes[j].NodeValue + '"');
    Memo2.Lines.Add('Всего атрибутов: ' + IntToStr(INode.AttributeNodes.Count));
  end;
end;
Цитата Сообщение от st_tsourkan Посмотреть сообщение
5. Надо научиться изменять вышеуказанные параметры (задавать свои).
Создание/изменение/удаление атрибута:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var
  INode : IXMLNode;
...
begin
...
  {Если элемент INode имеет атрибут с именем "style", то значение этого атрибута
  заменяется на "style_value". Если элемент не имеет атрибута с таким именем, то
  для этого элемента создаётся новый атрибут с именем "style" и его значение
  устанавливается равным "style_value".}
  INode.SetAttribute('style', 'style_value');
...
  {Если элемент INode имеет атрибут с именем 'style', то этот атрибут удаляется.}
  INode.AttributeNodes.Delete('style');
...
end;
Изменение значения элемента:
Delphi
1
2
3
4
5
6
7
var
  INode : IXMLNode;
begin
...
  INode.NodeValue := 'value';
...
end;
Создание нового элемента:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var
  INode, INodeNew : IXMLNode;
begin
...
  {К элементу INode добавляем дочерний элемент с тегом 'tag_new'. Новый дочерний
  элемент располагаем под индексом 0 - т. е. он становится первым в списке
  дочерних элементов.}
  INodeNew := INode.AddChild('tag_new', 0);
  INodeNew.NodeValue := 'value';
 
  {Или так:}
  INodeNew := XMLDocument1.CreateNode('tag_new', ntElement, 'value');
  INode.ChildNodes.Insert(0, INodeNew);
 
  {К элементу INode добавляем дочерний элемент с тегом 'tag_new'. Новый дочерний
  элемент располагаем в конце списка дочерних элементов.}
  INodeNew := INode.AddChild('tag_new');
  INodeNew.NodeValue := 'value';
 
  {Или так:}
  INodeNew := XMLDocument1.CreateNode('tag_new', ntElement, 'value');
  INode.ChildNodes.Add(INodeNew);
...
end;
Удаление элемента:
Delphi
1
2
3
4
5
6
7
8
9
var
  INode : IXMLNode;
begin
...
  {Если элемент INode имеет дочерний элемент с тегом 'tag_delete', то этот дочерний
  элемент удаляется.}
  INode.ChildNodes.Delete('tag_delete');
...
end;
7
0 / 0 / 0
Регистрация: 15.10.2013
Сообщений: 14
28.10.2013, 19:11  [ТС] 12
Mawrat, спасибо Вам огромное за информацию! Завтра, придя на свежую голову на работу, буду вникать и пробовать. Думаю, теперь-то уж точно справлюсь
0
670 / 560 / 242
Регистрация: 26.11.2012
Сообщений: 2,191
29.10.2013, 09:35 13
Можно как то этот манул "закрепить" в разделе форума? Очень подробно все рассписано!!!!!
0
13107 / 5888 / 1707
Регистрация: 19.09.2009
Сообщений: 8,808
29.10.2013, 11:49 14
Для закрепления, тема, всё-таки, должна быть более развёрнуто проработана.

Добавлено через 3 минуты
Если объединить со сведениями, например, из этой темы: Программа редактирования XML - документа
и добавить ряд дополнительных материалов, вот тогда можно было бы закрепить.
0
29.10.2013, 11:49
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
29.10.2013, 11:49
Помогаю со студенческими работами здесь

Ко всем файлам добавилось .xml, теперь они в формате ***.xls.XML, ***doc.XML (изначально в Word и Excel)
при копировании с одного ноутбука на другом (изначально на новом не было офиса, м.б. из-за этого...

Как работать с XML?
Подскажите вот такое дело пишем 5мес прогу по конвертации алгортмов из с билдер в дельфи и обртно в...

Как работать с XML?
Здравствуйте! Помогите, пожалуйста, как работать с XML, к примеру: мне нужна программа на Windows...

Как работать с xml?
Всем привет ! вот есть хмl &lt;r&gt; &lt;set var1=&quot;test1&quot; /&gt; &lt;conf&gt;test2&lt;/conf&gt;

Как работать с XML в SQLServer?
К примеру в поле типа text у меня xml данные Могу ли я с помощью SQL запроса вытащить из этого...

как работать с xml-файлом?
Задача заключается в следующем: как из xml-файла, выдернуть данные (с помощью какого свойства,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru