Как вы уже сказали, вы не можете использовать 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.
Благодарим за ответ! Но это не помогает в моем случае. Основная проблема заключается в том, что мой XML имеет динамические поля, он часто меняет свое имя, поэтому я не могу использовать XmlMapper. Я ищу способ создания полей во время выполнения, не зная их имен и количества. – WellingtonD
Большое вам спасибо! Это очень помогло. Поскольку вы подозревали, что мои XML-файлы содержат более одного «тега данных» внутри тега «datas». Поэтому я внес некоторые изменения, и это работает очень хорошо. – WellingtonD
Рад, что это помогло. Я отредактирую раздел о XmlMapper, чтобы он был короче. – MartynA