Завантаження XML у DataSet
Підкажіть, який є оптимальний підхід у цьому питанні
XML буває різний (тому що структура документа XML то, можливо практично довільної) Оптимальний підхід у цьому питанні: 1. Подивитися чи не реалізував хтось раніше завдання (Наприклад ClientDataSet вміє зберігати і завантажувати свій вміст у XML.) 2. Якщо ні, писати парсинг XML документа. (Розобрати вміст документа). Битися головою в стіну не треба їсти готові парсери (MS XML), Вам залишається використовувати їх для аналізу вмісту XML. PS Телепатичні здібності майже повністю розтратив учора, непогано б ставити питання конкретніше :)))
Мене цікавить саме варіант 1. Файл XML формується з іншої програми, вивантаження певної таблиці. Мені потрібно взяти цей файл та завантажити у свій набір даних. Як це простіше та/або правильніше зробити? При використанні ClientDataSet потрібен файл трансформації, як його створити? Чи є альтернатива ClientDataSet, тобто інший DataSet, який би завантажував XML?
Та я вчора питав також тільки нічого не валить! Файл трансформації створи через XML Mapper (утиліта в Дельфі така). Потім створи Data Packet, який і сидітиме у тебе в СlientDataSet"e:
procedure TForm1.Button1Click(Sender: TObject); const trans="c:\settings.xtr"; begin XMLTransform1.SourceXmlFile:="c:\settings.xml"; XMLTransform1.TransformationFile:=trans; ClientDataSet1.Close; ClientDataSet1.XMLData:=XMLTransform1.Data; ClientDataSet1.Open; end;
цей код створює Data Packet із XML фаїлу! Проблема в тому, як потім все завантажене зберегти в таблиці? Така штука не працює: XMLTransformClient1.ApplyUpdates("c:\settings.xml","c:\settings.xtr",-1); Вона постійно викидаєпомилку: Parser Error at the top of docoment Line 1 Position 1. Чого я тільки не робив і XML фаїл виправляв і схеми різні перепробував-не оре! Тут мені підказали, що треба Файл трансформації як Insert Delta зберігати! І все, а так 10 відповідей було і все на тему міркувань (що тут часто буває.)
Дякую. Хотілося б ще варіанти почути. На www.torry.net є відповідний імпорт, але ці компоненти платні.
Це була репліка на [4]І все, а так 10 відповідей було і все на тему міркувань (що тут часто і буває.)Вибач, якщо ти вирішив, що це стосується тебе
>Незнайка2003 А яка у тебе БД?
Ніяка, у цій задачі DataSet у пам'яті.
>bushmen Мені уроки з програмування не потрібні і я не сумніваюся, що в цьому розділі та й напевно в багатьох інших знаюся не гірше, а може і краще за Вас, ув. тов. Bushmen! У мене виникло питання і я його корректно задаю і не благаю що б мені хтось відповів, але й не прошу що б мені бейцли крутили різного роду заморочками, на кшталт: а навіщо тобі це треба або використовуй методи сервера. То може мені взагалі космічну енергію використати чи магію! Коли я бачу питання і не знаю відповіді, я не лізу в перших рядах коментувати ситуацію-навіщо людину помилятися. Є точна відповідь- тоді його даю! З повагою!
> Max_ У мене все працювало так: 1. Створив ClientDataSet із Persistent-полями. 2. У дизайн-таймі через його контекстне меню: Create DataSet, Save to MyBase XML table (задає ім'я файлу) 3. У XMLMapper-і: Open DataPacket (отриманий у 2. файл), Open XML Document (XML, кіт. Ти хочеш залити в базу), визначаєш відповідність полів, задаєш направл. перетворення та тип дельти, тестуєш файл файл трансформації назаданих файлах та зберігаєш його.
>Max_ На завершення [13]: Ну а потім використовуєш отриманий перевірений файл трансформації без проблем (майже :))
Ok, а як ти все у базі зберігаєш? Адже я хочу з XML в базу зберегти. У мене ClientDataSet приєднано до порожньої таблиці в базі і є XML з якого завантажити. DataPacket та Transformation file у мене є, завантажити все це в ClientDataSet1.XMLData теж можу, але в таблицю як зберегти?
Незнайка2003 Ну, не знаю, чого в ClientDataSet (тобто в Borland MIDAS) зайвого, швидше навпаки - хотілося б більшого, а те, що є, ІМХО, варто використовувати. А dll начебто одна - MIDAS.DLL, але можна і без неї - якщо додати в uses MidasLib.
Начебто двома способами виходить: 1. Через ClientDataSet.ApplyUpdates, якщо ти в нього заздалегідь саме дельту завантажив, а не просто набір записів. 2. Як ти сам сказав - через XMLTransformClient.ApplyUpdates, знову-таки, якщо йому як параметр інсерт-дельта XML-дані передавати.
Можна в порядку розширення кругозору зберегти CDS, у якого ChangeCount>0 в XML-файл і подивитися, чим змінені записи (тобто Delta) відрізняються від звичайних.
А як мені дельту завантажити, якщо вона read-only? В тому раз у раз, що завантажується XMLData, а не Delta! І як встановити інсерт-дельту (саме інсерт)?
Ну, ось я спочатку вивантажую з DBGRidEh усі виділені рядки в XML через ClientDataSet:
На формі лежать: dbGrid - грати DBGridEh dtGrid - її набір даних cdtExportSales - клієнтський набір даних
procedure Tfrb_Client.actExportExecute(Sender: TObject); var i,j: integer; begin з dbGrid.DataSource.Dataset do begin DisableControls; cdtExportSales.Close; // Створюємоклієнтський набір даних cdtExportSales.FieldDefs.Assign(dtGrid.FieldDefs); //. за зразком cdtExportSales.CreateDataSet; cdtExportSales.Open;
try for I := 0 to dbGrid.SelectedRows.Count - 1 do // Перекачуємо всі begin // виділені рядки Bookmark := dbGrid.SelectedRows.Items[I]; cdtExportSales.Insert; for j:= 0 до cdtExportSales.FieldCount - 1 do begin cdtExportSales.FieldByName(dtGr >dtGrid.Fields[j].Value; end; cdtExportSales.Post; end; frm_ExportClient.CreateAndShowModal([integer(cdtExportSales)]) // Тут запитуємо у користувача ім'я файлу, // куди експортувати, і експортуємо його finally EnableControls; cdtExportSales. Close; end; end; dbGrid.Selection.UpdateState; end;
//----------- Фрагмент процедури експорту:
var cdtExportSales : TClientDataSet; addr: Integer; begin inherited; sdExport.FileName := lblPathName.Caption + // Формуємо ім'я файлу - sdExport - це лежить на формі TSaveDialog dbEdEhPrefix.Text + FormatDateTime("_YYYYMMDDHHMMSS",Now)+ Root_Ex .XML"; if sdExport.Execute then begin lblPathName.Caption := ExtractFilePath(sdExport.FileName);
(Sender as TBitBtn). Enabled := False; try addr := a_params[0]; cdtExportSales := TClientDataSet(addr); if cdtExportSales.RecordCount > 0 then ExportClients(cdtExportSales) else begin ShowMessage("Немає даних!"); end finally (Sender as TBitBtn).Enabled := True; end end end;
//-------------- Ну, і сама процедура експорту var i: Integer; FileName: string; f: file of byte; begin lblMsgSales.Caption := "Експорт даних."; try
FileName := lblPathName.Caption + dbEdEhPrefix.Text + FormatDateTime("_YYYYMMDDHHMMSS",Now)+ Root_Exp_C + ".XML";
if not FileExists(FileName) then raise Exception.Create("Файл "+FileName+" Не було створено");
AssignFile(f,FileName); try Reset(f); if FileSize(f) = 0 then raise Exception.Create("Файл "+FileName+ " був створений з нульовою довжиною" + #10 + "Можливо, мало місця! "); finally CloseFile(f) end;
except on E: Exception do begin; lblMsgSales.Caption := "Помилка!"; ShowMessage("Помилка при роботі з клієнтським набором даних:"#13+ e.Message);
РЕЗЮМЕ: 1. Створюємо набір даних: cdtExportSales.Close; // Створюємо клієнтський набір даних cdtExportSales.FieldDefs.Assign(dtGrid.FieldDefs); //. за зразком cdtExportSales.CreateDataSet; cdtExportSales.Open;
2. Закачуємо в нього дані з фізичного НД: cdtExportSales.FieldByName(dtGr &dtGrid.Fields[j].Value; 3. Експорт даних DtSet.SaveToFile(FileName, dfXML);
Всі. Імпорт – ще простіше:
Не треба її вантажити. -) Вона сама, ця Delta вийде, якщо ти в Data (або XML Data, що загалом те саме) завантажиш дані, що містять змінені записи, тобто. Delta – це відфільтрована Data. Delta з'являється при модифікації записів у ClientDataSet (Append, Delete, Edit/Post) або при завантаженні в нього даних, отриманих з використанням файлу трансформації типу інсерт або delete delta.
>Max_ У [20] Delta виходить явно за допомогою Insert: cdtExportSales.Insert; for j:= 0 до cdtExportSales.FieldCount - 1 do begin cdtExportSales.FieldByName(dtGr >dtGrid.Fields[j].Value; end; cdtExportSales.Post; , а у разі використання XMLTransform це робиться автоматично.
>Малиновський Володимир А в базу у Вас неапдейтується?
Все врешті-решт у базу заливається, інакше навіщо експорт робити – то було?
procedure TForm1.Button1Click(Sender: TObject); begin ClientDataSet1.Open; //Порожня Oracle таблиця. XMLTransform1.SourceXmlFile:="c:\channels.xml"; //Початковий XML XMLTransform1.TransformationFile:="c:\sett_trans.xtr"; //трансф. ClientDataSet1.XMLData:=XMLTransform1.Data; //генерую Data Packet if ClientDataSet1.Delta<>null then //перевіряю ShowMessage("Changed"); end; >а у разі використання XMLTransform це робиться автоматично. Перевірив дані з'явилися, а Delta як була порожньою так і залишилася!
>Max_ А c:\sett_trans.xtr" ти згенерував у XMLMapper як Insert Delta?
>Max_ Я б сказав if ClientDataSet1.ChangeCount>0 then //перевіряю
Все запрацювало. Дякую, sokohigh. До речі, а чи можна генерувати трансформаційний фаїл програмно (insert delta що б був)?
Нема за що ;) А ти подивися на цей файл (у IE, наприклад) - у принципі це ж текст. Тільки, звичайно, не дуже це зручно. Напевно простіше створювати допоміжний CDS, вантажити в нього дані з XML і з нього записи по одній апендити в CDS, прив'язаний до бази через провайдера. Можна, певне, і незалежно від структури зробити.
Коли прочитав про ці фічі ClientDataSet (усі разом Borland називає це BriefCase model), зрадів: ну, гадаю, ось і готовий BackUp/Restore для реляційної бази даних будь-якої структури. Типу робимо дерево з CDS-ів (за допомогою TDataSetField-ов), пишемо SQL для вилучення кожного листка дерева, робимо кореневого CDS опен, чекаємо звичайно, і робимо SaveToFile (знову чекаємо). Ось і готовий Backup усієї бази в одному XML-файлі. Ну і звичайно насамперед вирішив, що для рестора достатньо буде зробитиLoadFromFile та ApplyUpdate, наївний. але немає у світі досконалості (чи як там у класиків?) доводиться ще й трансформації створювати, тобто майже двічі описувати структуру. Адже це прикро: добре, коли потрібно довільний XML завантажити, а тут та сама структура і все одно створювай трансформацію. Загалом, негарне це рішення - із трансформаціями. Може, хто краще чого придумав? Було б дуже цікаво.