Einzelnen Beitrag anzeigen

Fukiszo
(Gast)

n/a Beiträge
 
#6

AW: Probleme mit XML Encoding

  Alt 25. Jan 2018, 15:24
damit wollt ich andeuten, du kennst ja dein problem und wollt auf soetwas in etwa hinaus, einen xml parser

Zitat:
Title: XML File Viewer

Question: How to create a simple XML File viewer, without worrying about the XML itself. The easiest solution is using the Microsoft XML Document Object Model, installed on every machine that run MS Internet Explorer 4 or higher.

Answer:
In this article I am showing you a simple XML file viewer, that may be extended to an XML editor with some work. You may enhance the editor by importing icons for the different node types, etc. That's up to you.

My main idea is to show you how to import type libraries from readily available components installed on nearly every machine in the modern windows world.

Note: The MS XML DOM is available for free download and redistribution at msdn.microsoft.com.

IMPORTING THE MS XML TYPE LIBRARY
=================================

Start Delphi and create a new application, I you haven't done so already. In the Delphi menu go to Project|Import Type Library... A dialog will appear on your screen, with a list of all installed and registered COM libraries available for import. Take a moment and scroll through it, you might be surprised.

Somewhere down the list you find Microsoft XML, version 2.0 (Version 2.0). This is the type library we are going to import. Additionally, you may see Microsoft XML, v3.0 (Version 3.0). This is a newer and faster version from MS, we are going to use the older version however, since it is more common.

After selecting the MS XML, version 2.0 component object, select a Unit Directory, and press the Create Unit button. The Install button will install the component in your Component Pallete, additionally.

PREPARING YOUR APPLICATION FORM
===============================

Drop a MainMenu (Standard) component on your form, and insert a Open Menu item (name: Open1).
Drop a TreeView (Win32) component on your form, set Align=alLeft and ReadOnly=True (name: trvStructure).
Drop an OpenDialog (Dialogs) component on your form (name: OpenDialog1).
Drop a Panel (Standard) component on your form, set Align=alClient and clear the Caption (name: Panel1).
Drop a StringGrid (Additional) component on the Panel1 set Align=alTop, RowCount=2, ColCount=2, FixedCols=0, FixedRows=1 (name: grdAttributes).
Drop a Memo (Standard) on the Panel1 set Align=alClient, ReadOnly=True (name mmoNodeContent).

Note: The names I have used will appear in the source code again!

A PSEUDO CLASS FOR THE XML INTERFACES
=====================================

Because mapping of interface via pointers introduces some problems I chose to create a simple class that contains only on variable holding the reference to the XML Node interface.

type
TXMLNodeWrapper = class
private
FNode: IXMLDOMNode;
protected
public
constructor Create(aNode: IXMLDOMNode);
property Node: IXMLDOMNode read FNode;
end;

The constructor will save the reference in the FNode variable.

CREATING THE XML DOM OBJECT
===========================

Creating an instance of the object is rather simple. Having a variable FDocument of the type IXMLDOMDocument, defined in the imported MSXML_TLB.

FDocument := CoDOMDocument.Create;

Next you need to set up the component to your needs.

FDocument.async := False;
FDocument.validateOnParse := True;
FDocument.preserveWhiteSpace := True;

The first I want to do is inserting an base element into the document. Every XML document needs at least this base element. I have named it xmlstart.

Note: Be careful, XML is case-sensitive.

FDocument.appendChild(FDocument.createNode(NODE_EL EMENT, 'xmlstart', ''));

PARSING THE XML DOCUMENT
========================

There are quite many ways of parsing XML. I want to show you two recursive ways, that are very similar, but have quite different results.

(1) NodeList := Node.childNodes;

Returns all children, inlcude some special node types, such as #text or #comment. These node types require special care.

(2) NodeList := Node.selectNodes('*');

Returns all standard node types, that can be accessed via XSL (XML Structured Language). These node types are easy in use.

ACCESSING THE NODE LIST
=======================

Accessing any item in a Node List is very easy. The length returns the count of items in the list (equal to Delphis Count property). The Item array gives access to every Item of the node list.

for I := 0 to Pred(XMLNodeList.length) do
ShowMessage(XMLNodeList.item[I].nodeName);

MORE INFORMATION ABOUT THE MS XML DOM
=====================================

The most important web addresses for the MS XML DOM are:

http://msdn.microsoft.com/xml (all about XML)
http://131.107.228.20/xquerydemo/demo.aspx (XML Query Language Demo)
http://msdn.microsoft.com/downloads/.../072/topic.xml (Downloads)

THE SOURCE CODE FOR THE XML VIEWER
==================================

unit uMainForm;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
MSXML_TLB, ComCtrls, Menus, Grids, ExtCtrls, StdCtrls;

type
TXMLNodeWrapper = class
private
FNode: IXMLDOMNode;
protected
public
constructor Create(aNode: IXMLDOMNode);
property Node: IXMLDOMNode read FNode;
end;

TfrmMain = class(TForm)
MainMenu1: TMainMenu;
File1: TMenuItem;
Open1: TMenuItem;
trvStructure: TTreeView;
OpenDialog1: TOpenDialog;
Panel1: TPanel;
grdAttributes: TStringGrid;
mmoNodeContent: TMemo;
procedure FormCreate(Sender: TObject);
procedure Open1Click(Sender: TObject);
procedure trvStructureChange(Sender: TObject; Node: TTreeNode);
private
FDocument: IXMLDOMDocument;
FFileName: String;
procedure LoadXML;
public
end;

var
frmMain: TfrmMain;

implementation

{$R *.DFM}

{ TXMLNodeWrapper }

constructor TXMLNodeWrapper.Create(aNode: IXMLDOMNode);
begin
inherited Create;
FNode := aNode;
end;

{ TFrmMain }

procedure TfrmMain.FormCreate(Sender: TObject);
begin
FDocument := CoDOMDocument.Create;
FDocument.async := False;
FDocument.validateOnParse := True;
FDocument.preserveWhiteSpace := True;
FDocument.appendChild(FDocument.createNode(NODE_EL EMENT, 'xmlstart', ''));

grdAttributes.Cells[0, 0] := 'Attribute name';
grdAttributes.Cells[1, 0] := 'Attribute value';
end;

procedure TfrmMain.LoadXML;
procedure EnterNode(const XMLNode: IXMLDOMNode; TreeNode: TTreeNode);
var
I: Integer;
XMLNodeList: IXMLDOMNodeList;
NewTreeNode: TTreeNode;
begin
NewTreeNode := trvStructure.Items.AddChild(TreeNode, XMLNode.nodeName);
NewTreeNode.Data := TXMLNodeWrapper.Create(XMLNode);
// use XMLNode.childNodes to get all nodes (incl. special types)
XMLNodeList := XMLNode.selectNodes('*');
for I := 0 to Pred(XMLNodeList.length) do
EnterNode(XMLNodeList.item[I], NewTreeNode);
end;
begin
for I := 0 to trvStructure.Items.Count - 1 do
TXMLNodeWrapper(trvStructure.Items.Item[I].Data).Destroy;
trvStructure.Items.BeginUpdate;
try
trvStructure.Items.Clear;
EnterNode(FDocument.documentElement, nil);
finally
trvStructure.Items.EndUpdate;
end;
end;

procedure TfrmMain.Open1Click(Sender: TObject);
begin
if OpenDialog1.Execute then
begin
FDocument.load(OpenDialog1.FileName);
FFileName := OpenDialog1.FileName;
LoadXML;
end;
end;

procedure TfrmMain.trvStructureChange(Sender: TObject; Node: TTreeNode);
var
I: Integer;
CurrentNode: IXMLDOMNode;
begin
CurrentNode := TXMLNodeWrapper(Node.Data).Node;
Caption := CurrentNode.nodeName;
if CurrentNode.selectNodes('*').length = 0 then
mmoNodeContent.Text := CurrentNode.text
else
mmoNodeContent.Text := '';
if CurrentNode.attributes.length 0 then
begin
grdAttributes.RowCount := Succ(CurrentNode.attributes.length);
grdAttributes.FixedRows := 1;
for I := 0 to Pred(CurrentNode.attributes.length) do
begin
grdAttributes.Cells[0, Succ(I)] := CurrentNode.attributes.item[I].nodeName;
grdAttributes.Cells[1, Succ(I)] := CurrentNode.attributes.item[I].text;
end;
end else begin
grdAttributes.RowCount := 2;
grdAttributes.Cells[0, 1] := '';
grdAttributes.Cells[1, 1] := '';
end;
end;

end.
man könnte die Namensfelder per Parser "korrigieren", falls das helfen könnte.

grüße
  Mit Zitat antworten Zitat