2016-02-15 1 views
0

Я пытаюсь загрузить файл XML в набор данных Delphi с использованием mydataset.loadfromfile("myfile.xml")Загрузить динамическое XML в наборе данных

Проблема в том, что я не знаю, имена полей XML и сколько полей имеет. Я знаю, что XML имеет только один уровень, например:

<DOCTO id ="3892" usuario="2" data="22/12/2015 10:33:22"> 
    <CONDUTA_1>teste conduta 1</CONDUTA_1> 
    <CONDUTA_2>teste conduta 2</CONDUTA_2> 
</DOCTO> 

Я ищу способ, чтобы загрузить XML без до создания полей.

ответ

5

Как вы уже сказали, вы не можете использовать XMLMapper, я переместил этот раздел моего ответа на дно.

Поскольку вы не можете использовать XmlMapper, вам необходимо проанализировать XML самостоятельно, используя синтаксический анализатор XML. В приведенном ниже примере используется XML DOM Parser, который поставляется с Windows, для которого вам нужен MSXML в вашем списке Uses. Чтобы проиллюстрировать, как сделать это, я собираюсь использовать XML с той же структурой, что и ваш, но с абстрактным узлом - и именами атрибутов, чтобы избежать того, чтобы имена узлов и значения вашего XML были отвлекающими.

<data a1="a" a2="b" a3="c"> 
    <r1>11111</r1> 
    <r2>22222</r2> 
</data> 

На одном полюсе, имена полей могут быть имена a1, a2, a3 из атрибутов <data> узла и значения полей могут быть значения этих атрибутов.

Как их получить в режиме LoadFromAttributes. В основном, он загружает XML в объект XMLDoc, использует запрос XPath, чтобы найти узел <data>, и их получает свои атрибуты для создания полей набора данных и установки их значений.

С другой стороны, подэлементы <r1> и <r2> могут быть именами полей и их текстовыми текстами , значениями полей. Процедура LoadFromNodes показывает, как это сделать.

Конечно, на практике sematics вашего XML может означать, что имена полей и значения представляют собой смесь из двух, но, как вы ничего не сказали о том, какие ваши XML «означает», я Вам придется оставить это для вас.

TForm1 = class(TForm) 
    Memo1: TMemo; 
    CDS1: TClientDataSet; 
    DataSource1: TDataSource; 
    DBGrid1: TDBGrid; 
    btnAttributes: TButton; 
    btnFromNodes: TButton; 
    procedure FormCreate(Sender: TObject); 
    procedure btnAttributesClick(Sender: TObject); 
    procedure btnFromNodesClick(Sender: TObject); 
    public 
    XMLDoc : IXMLDOMDocument; 
    procedure PrepareCDS; 
    procedure LoadFromAttributes; 
    procedure LoadFromNodes; 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

const 
    scXML = 
    '<data a1="a" a2="b" a3="c">'#13#10 
    + ' <r1>11111</r1>'#13#10 
    + ' <r2>22222</r2>'#13#10 
    + '</data>'; 

    scRootNodeName = 'data'; 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    XmlDoc := CoDOMDocument.Create; 
    XmlDoc.Async := False; 
    XMLDoc.loadXML(scXML); 
    Memo1.Lines.Text := scXML; 
end; 

procedure TForm1.LoadFromAttributes; 
var 
    PathQuery : String; 
    NodeList : IXmlDOMNodeList; 
    Node, 
    AttrNode : IXmlDomNode; 
    Attributes : IXMLDOMNamedNodeMap; 
    Field : TField; 
    i : Integer; 
begin 
    PrepareCDS; 

    PathQuery := scRootNodeName; 
    NodeList := XMLDoc.SelectNodes(PathQuery); 
    Assert(NodeList.Length > 0); 
    Node := NodeList.item[0]; 
    Attributes := Node.attributes; 
    for i := 0 to Attributes.Length - 1 do begin 
    AttrNode := Attributes.item[i]; 
    Field := TStringField.Create(Self); 
    Field.Size := 80; 
    Field.FieldName := AttrNode.nodeName; 
    Field.DataSet := CDS1; 
    end; 

    CDS1.CreateDataSet; 

    CDS1.Insert; 
    for i := 0 to Attributes.Length - 1 do begin 
    AttrNode := Attributes.item[i]; 
    CDS1.Fields[i].Value := AttrNode.nodeValue; 
    end; 
    CDS1.Post; 
end; 

procedure TForm1.LoadFromNodes; 
var 
    PathQuery : String; 
    NodeList : IXmlDOMNodeList; 
    Node, 
    AttrNode : IXmlDomNode; 
    Field : TField; 
    i : Integer; 
begin 
    PrepareCDS; 

    PathQuery := scRootNodeName + '/*'; 
    NodeList := XMLDoc.SelectNodes(PathQuery); 
    Assert(NodeList.Length > 0); 
    for i := 0 to NodeList.Length - 1 do begin 
    Node := NodeList.item[i]; 
    Field := TStringField.Create(Self); 
    Field.Size := 80; 
    Field.FieldName := Node.nodeName; 
    Field.DataSet := CDS1; 
    end; 

    CDS1.CreateDataSet; 

    CDS1.Insert; 
    for i := 0 to NodeList.Length - 1 do begin 
    Node := NodeList.item[i]; 
    CDS1.Fields[i].Value := Node.Text; 
    end; 
    CDS1.Post; 
end; 

procedure TForm1.PrepareCDS; 
begin 
    if CDS1.Active then 
    CDS1.Close; 
    CDS1.FieldDefs.Clear; 
    CDS1.Fields.Clear; 
end; 

procedure TForm1.btnAttributesClick(Sender: TObject); 
begin 
    LoadFromAttributes; 
end; 

procedure TForm1.btnFromNodesClick(Sender: TObject); 
begin 
    LoadFromNodes; 
end; 

Как вы можете видеть, все это довольно просто с небольшим знакомством с анализатором MS XML и использованием XPath (хотя в этом случае структура XML настолько просто, вы на самом деле не нужны используйте XPath, чтобы добраться до него).

В вашем случае это не применимо, но если ваша структура XML исправлена ​​заранее, вы можете использовать утилиту XmlMapper, которая поставляется с Delphi, чтобы определить файл сопоставления, чтобы преобразовать его в формат, используемый TClientDataSet , Затем вы можете использовать TClientDataSet в сочетании с другим компонентом TXmlTransformProvider, который использует файл преобразования для загрузки ваших данных в CDS. Дальнейшие подробности здесь:

Parsing xml file Delphi

Btw, рискуя констатирую очевидное, если ваш файл .xml на самом деле имеет несколько <DOCTO> узлов, вам необходимо поместить их в корневой узел так, чтобы файл имеет действительную структуру XML.

+0

Благодарим за ответ! Но это не помогает в моем случае. Основная проблема заключается в том, что мой XML имеет динамические поля, он часто меняет свое имя, поэтому я не могу использовать XmlMapper. Я ищу способ создания полей во время выполнения, не зная их имен и количества. – WellingtonD

+0

Большое вам спасибо! Это очень помогло. Поскольку вы подозревали, что мои XML-файлы содержат более одного «тега данных» внутри тега «datas». Поэтому я внес некоторые изменения, и это работает очень хорошо. – WellingtonD

+0

Рад, что это помогло. Я отредактирую раздел о XmlMapper, чтобы он был короче. – MartynA

Смежные вопросы