Консультация № 183230
18.05.2011, 18:04
68.84 руб.
0 10 1
Уважаемые эксперты! Пожалуйста, ответьте на вопрос:
Нужно написать программу, принимающую на вход текстовый CSV-файл, содержащий произвольную таблицу со значениями, разделенными запятой, и преобразующую содержание этого файла в XML формат. Первая строка CSV файла содержит названия полей. Следующий пример показывает принцип формирования выходного XML файла:

Вход:
Город, ТипУлицы, Улица
Таганрог, улица,Ленина
Ростов, улица,Б.Садовая
Москва,проспект,Жукова

Выход:
<RECORDS>
<RECORD id=”1”>
<FIELD name=”Город” value=”Таганрог” />
<FIELD name=”ТипУлицы” value=”улица” />
<FIELD name=”Улица” value=”Ленина” />
<RECORD />
<RECORD id=”2”>
<FIELD name=”Город” value=”Ростов” />
<FIELD name=”ТипУлицы” value=”улица” />
<FIELD name=”Улица” value=”Б.Садовая” />
<RECORD />
<RECORD id=”3”>
<FIELD name=”Город” value=”Москва” />
<FIELD name=”ТипУлицы” value=”проспект” />
<FIELD name=”Улица” value=”Жукова” />
<RECORD />
</RECORDS>

P.S. Сделал так чтобы csv файл читался и данные попадали в StringGrid,потом логически понимаю что нужно построить структуру xml файла и из StringGrid выгрузить в xml,но как это сделать я не знаю...с xml никогда не работал,помогите пожалуйста
Возможно и не надо помещать данные в StringGrid,если правильно понимаю то память тратится в пустую...

Обсуждение

Неизвестный
19.05.2011, 10:58
общий
19.05.2011, 13:12
Совсем не обязательно грузить данный файл в StringGrid.

Алгоритм работы будет такой:
1. Пока не кончились строки делаем
2. Получаем строку из файла
3. Преобразуем ее в список значений
4. Если это самая первая строка, то принимаем её за заголовки. и идем на 2
5. формируем узел XML файла


Код:
procedure ExtractData(Data: string; const Values: TStrings);
{ Процедура преобразует данные хранящиеся в строке с разделителем "," в список значений}
begin
{Данный алгоритм будет работать в Delphi 2009 и выше для младших версий
необходимо "вручную" разбирать данную строку и заполнять список}
Values.Clear;
Values.LineBreak := ',';
Values.Text := Data;
end;

function XMLRecord(XMLParentNode: IXMLNode; RecordIndex: Cardinal;
RecordHeader, RecordValues: TStrings): IXMLNode;
{ функция возвращает ссылку на ужел в основном XML документе для данной записи
XMLParentNode - корневой узел XML документа
RecordIndex - порядковый новер записи
RecordHeader - заголовок записи
RecordValues - значения записи}
var
XMLField: IXMLNode;
i: Integer;
begin
if RecordHeader.Count <> RecordValues.Count then begin
Result := nil;
Exit;
end;

Result := XMLParentNode.AddChild('RECORD');
Result.Attributes['id'] := RecordIndex;
for i := 0 to RecordHeader.Count - 1 do begin
XMLField := Result.AddChild('FIELD');
XMLField.Attributes['name'] := RecordHeader[i];
XMLField.Attributes['value'] := RecordValues[i];
end;
end;

procedure ConvertCSVToXML(CSVFile: TFileName; XMLDoc: TXMLDocument);
{ Процедура преобразует входящий CSVFile в XML документ}
var
fCSV: TextFile;
sData: string;
slHeader: TStringList;
slRecord: TStringList;
iRecordIndex: Cardinal;
begin
slHeader := TStringList.Create;
slRecord := TStringList.Create;
AssignFile(fCSV, CSVFile);
Reset(fCSV);
if not Eof(fCSV) then begin
XMLDoc.Active := True;
XMLDoc.DocumentElement := XMLDoc.CreateNode('RECORDS');
iRecordIndex := 0;
end;
while not Eof(fCSV) do begin
Readln(fCSV, sData);
if iRecordIndex = 0 then begin
Inc(iRecordIndex);
ExtractData(sData, slHeader);
Continue;
end;

ExtractData(sData, slRecord);
XMLRecord(XMLDoc.DocumentElement, iRecordIndex, slHeader, slRecord);
Inc(iRecordIndex);
end;
CloseFile(fCSV);
slHeader.Free;
slRecord.Free;
end;

procedure TForm1.btnconvertClick(Sender: TObject);
begin
lstXML.Clear;
xmldcmnt1.Active := False;
ConvertCSVToXML(lbledtFilename.Text, xmldcmnt1);
lstXML.Items.Text := FormatXMLData(xmldcmnt1.XML.Text);
end;


во вложении находиться проект для Delphi 2010
Прикрепленные файлы:
9f935f7e2e530d73285e73b94b121ed7.zip
Неизвестный
19.05.2011, 13:30
общий
добрый день!А на delphi7 будет работать?
Неизвестный
19.05.2011, 14:29
общий
19.05.2011, 14:54
Ещё раз добрый день!
Создал .csv файл,туда поместил вот это Город, ТипУлицы, Улица
Таганрог, улица,Ленина
Ростов, улица,Б.Садовая
Москва,проспект,Жукова
запустил конвертацию
выдало в лист боксе структуру xml файла но в значениях name и value всякая белиберда,иероглифы,связано с кодировкой?или то что открывается проект в delphi 7 ?

p.s. если вас не сильно затруднит,можете прокомментировать строчки кода в процедурах
Неизвестный
19.05.2011, 22:40
общий
Также необходимо соблюсти формат выходного файла
Выход:
<RECORDS>
<RECORD id=”1”>
<FIELD name=”Город” value=”Таганрог” />
<FIELD name=”ТипУлицы” value=”улица” />
<FIELD name=”Улица” value=”Ленина” />
<RECORD />
<RECORD id=”2”>
<FIELD name=”Город” value=”Ростов” />
<FIELD name=”ТипУлицы” value=”улица” />
<FIELD name=”Улица” value=”Б.Садовая” />
<RECORD />
<RECORD id=”3”>
<FIELD name=”Город” value=”Москва” />
<FIELD name=”ТипУлицы” value=”проспект” />
<FIELD name=”Улица” value=”Жукова” />
<RECORD />
</RECORDS>
помогите пожалуйста добить задание
давно
Мастер-Эксперт
425
4118
20.05.2011, 06:07
общий
20.05.2011, 06:07
А Вы просто с текстовым файлом умеете работь? Ведь XML-файл - это обычный текстовый файл, только в нем должны присутствовать некие обязательные строки, например заголовочная строка <?xml version="1.0" ?>. Всё остальной записывается в файл именно в том виде, в каком Вы привели у себя в примере.
Единственная проблема - XML-файл обычно должен быть в кодировке UTF-8. У Вас в какой кодировке должен быть файл?
Об авторе:
Я только в одном глубоко убеждён - не надо иметь убеждений! :)
Неизвестный
20.05.2011, 07:29
общий
Да,вроде как могу.только мне не понятно как например формировать
<RECORD id=”1”>
<FIELD name=”Город” value=”Таганрог” />
<FIELD name=”ТипУлицы” value=”улица” />
<FIELD name=”Улица” value=”Ленина” /> эту часть

Если честно,то про кодировку никто ничего не говорил,наверно в кодировке UTF-8
Неизвестный
20.05.2011, 11:07
общий
Во вложении лежит оттестированый проект в Delphi 2010/2006 (должен пойти и на 7)
с коментариями к каждой фунции за исключением ExtractData (там и так все должно быть понятно)
теперь XML документ формируется в кодировке Windows-1251, поэтому должен нормально отображаться в Delphi 7/2006/2010.
документ фориатируется в ListBox'е для удобства чтения и оценки результата. Как необходимо форматировать документ описано в процедуре конверирования, поэтому сохраняемый файл будет в нужном форматировании и кодировке.
Прикрепленные файлы:
0fdc5217ecfb99eb11c633e9656c1be6.rar
Неизвестный
20.05.2011, 12:15
общий
Ночью скачал Delphi 2009,скомпилил проект,запустил и всё заработало!)Большое спасибо,что уделили своё время
давно
Мастер-Эксперт
425
4118
21.05.2011, 03:34
общий
Можете это писать в ответе.
Об авторе:
Я только в одном глубоко убеждён - не надо иметь убеждений! :)
Неизвестный
25.05.2011, 19:21
общий
это ответ
Здравствуйте, angel.nero!
Поскольку Striker Loner пропал, отвечаю на основании его ответа из мини-форума.
Совсем не обязательно грузить данный файл в StringGrid.

Алгоритм работы будет такой:
1. Пока не кончились строки, делаем.
2. Получаем строку из файла.
3. Преобразуем её в список значений.
4. Если это самая первая строка, то принимаем её за заголовки и идем на 2.
5. Формируем узел XML файла.

[code h=100]procedure ExtractData(Data: string; const Values: TStrings);
{ Процедура преобразует данные хранящиеся в строке с разделителем "," в список значений}
begin
{Данный алгоритм будет работать в Delphi 2009 и выше для младших версий
необходимо "вручную" разбирать данную строку и заполнять список}
Values.Clear;
Values.LineBreak := ',';
Values.Text := Data;
end;

function XMLRecord(XMLParentNode: IXMLNode; RecordIndex: Cardinal;
RecordHeader, RecordValues: TStrings): IXMLNode;
{ функция возвращает ссылку на ужел в основном XML документе для данной записи
XMLParentNode - корневой узел XML документа
RecordIndex - порядковый новер записи
RecordHeader - заголовок записи
RecordValues - значения записи}
var
XMLField: IXMLNode;
i: Integer;
begin
if RecordHeader.Count <> RecordValues.Count then begin
Result := nil;
Exit;
end;

Result := XMLParentNode.AddChild('RECORD');
Result.Attributes['id'] := RecordIndex;
for i := 0 to RecordHeader.Count - 1 do begin
XMLField := Result.AddChild('FIELD');
XMLField.Attributes['name'] := RecordHeader[i];
XMLField.Attributes['value'] := RecordValues[i];
end;
end;

procedure ConvertCSVToXML(CSVFile: TFileName; XMLDoc: TXMLDocument);
{ Процедура преобразует входящий CSVFile в XML документ}
var
fCSV: TextFile;
sData: string;
slHeader: TStringList;
slRecord: TStringList;
iRecordIndex: Cardinal;
begin
slHeader := TStringList.Create;
slRecord := TStringList.Create;
AssignFile(fCSV, CSVFile);
Reset(fCSV);
if not Eof(fCSV) then begin
XMLDoc.Active := True;
XMLDoc.DocumentElement := XMLDoc.CreateNode('RECORDS');
iRecordIndex := 0;
end;
while not Eof(fCSV) do begin
Readln(fCSV, sData);
if iRecordIndex = 0 then begin
Inc(iRecordIndex);
ExtractData(sData, slHeader);
Continue;
end;

ExtractData(sData, slRecord);
XMLRecord(XMLDoc.DocumentElement, iRecordIndex, slHeader, slRecord);
Inc(iRecordIndex);
end;
CloseFile(fCSV);
slHeader.Free;
slRecord.Free;
end;

procedure TForm1.btnconvertClick(Sender: TObject);
begin
lstXML.Clear;
xmldcmnt1.Active := False;
ConvertCSVToXML(lbledtFilename.Text, xmldcmnt1);
lstXML.Items.Text := FormatXMLData(xmldcmnt1.XML.Text);
end;[/code]

Во вложении лежит оттестированый проект в Delphi 2010/2006 (должен пойти и на 7) с комментариями к каждой функции, за исключением ExtractData (там и так все должно быть понятно).
Теперь XML документ формируется в кодировке Windows-1251, поэтому должен нормально отображаться в Delphi 7/2006/2010.
Документ форматируется в ListBox'е для удобства чтения и оценки результата. Как необходимо форматировать документ, описано в процедуре конвертирования, поэтому сохраняемый файл будет в нужном форматировании и кодировке.
Прикрепленные файлы:
Форма ответа