Entwickler-Ecke

Internet / Netzwerk - Einlesen eines XML-Documents aus dem Internet?


Schosch - Sa 04.02.12 15:12
Titel: Einlesen eines XML-Documents aus dem Internet?
Also Ich arbeite gerade an einem Programm, welches in der Lage sein soll 10 Beträge verschiedener Währungen in einem einzigen Eurowert auszugeben. Die wechselkurse sollen aus dem Internet aktuallisiert werden. Hierfür verwende ich folgende API:

http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml

Diese Api ist ein XML-Document, und jetzt versuche ich halt auf die 10 entsprechenden Knotenpunkte dieses Documents zuzugreifen. Hier ist der entsprechende Ausschnitt aus meinem Quellcode:



Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
uses
  ...IdHTTP, DOM, XMLRead, XMLWrite;

procedure TForm1.FormCreate(Sender: TObject);
var PassNode :TDOMNode;
    API: TIdHttp;
    Doc: TXMLDocument;
begin
  Doc:=TXMLDocument.Create;
  API:=TIdHTTP.Create;

  API.Get('http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml');
  ReadXMLFile(Doc,API);

// Die Wechselkurse sind erstmal Lokal im Programm, doch hier sollen anstadt die 
// Lokalen Werte die entsprechenden Werte aus der API stehen.
  Waehrungen[0]:=1.2332;      //Australien
  Waehrungen[1]:=8.2179;      //China
  Waehrungen[2]:=1.3129;      //Canada
  Waehrungen[3]:=7.4358;      //Dänemark
  Waehrungen[4]:=0.83625;     //Groß Britanien
  Waehrungen[5]:=65.0780;     //Indien
  Waehrungen[6]:=100.10;      //Japan
  Waehrungen[7]:=8.7791;      //Schweden
  Waehrungen[8]:=1.2061;      //Schweiz
  Waehrungen[9]:=1.3017;      //USA


ind der zeile (ReadXMLFile(Doc,API);) kommt eine Fehlermeldung:

Unit1.pas(722,22) Error: Incompatible type for arg no. 2: Got "TIdHTTP", expected "TStream"

keine Ahnung was die genau bedeutet. Ich vermute mal das ich hier eine Rückgabetyp-Umwandlung vornehmen muss, nur wüsste ich auch nicht wie diese aussieht, da dies mein erstes Projekt im zusammenhang mit dem indernet und einem XML-Documents ist... Also bitte ich hier um Hilfe.

Moderiert von user profile iconNarses: Titel geändert.


jaenicke - Sa 04.02.12 15:40

Das hat nichts mit einer Rückgabetyp-Umwandlung zu tun. Denn den Rückgabewert wirfst du ja weg beim Aufruf von Get.

Du versuchst an ReadXMLFile statt den XML-Daten ein IdHttp-Objekt zu übergeben. Das ist wie wenn du zur Passkontrolle statt den Pass vom Mitarbeiter der Passausgabestelle zu holen den Mitarbeiter mitnimmst und bei der Passkontrolle versuchst abzugeben...

Schau dir einmal den zweiten Parameter von Get an. Da kannst du einen TMemoryStream übergeben, damit dort die Daten der Seite reingeschrieben werden. Den Stream kannst du dann wiederum an ReadXMLFile übergeben.


Schosch - Sa 04.02.12 17:27

Achsoo, ich hab das jetzt so versuch:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
procedure TForm1.FormCreate(Sender: TObject);
var PassNode :TDOMNode;
    API: TIdHttp;
    Doc: TXMLDocument;
    Internetverbindung: Boolean;

begin
  Internetverbindung:=true;
  Doc:=TXMLDocument.Create;
  API:=TIdHTTP.Create;

  try
    API.Get('http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml');
    ReadXMLFile(Doc,'http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml');
  except
    Internetverbindung:=false;
    Showmessage('Keine Internet-verbindung möglich');
  end;

  if Internetverbindung=true then
    begin
      PassNode := Doc.DocumentElement.FindNode('USD');
      WriteLn(PassNode.NodeValue);
      WriteLn(PassNode.FirstChild.NodeValue);
    end;
end;

aber hier gibt das programm immer die Showmessage aus..


jaenicke - Sa 04.02.12 17:48

user profile iconSchosch hat folgendes geschrieben Zum zitierten Posting springen:
Achsoo, ich hab das jetzt so versuch:
Mach es doch stattdessen wie ich geschrieben habe.
Oder du übergibst den Rückgabewert von Get als zweiten Parameter an ReadXMLFile. Das scheint ja auch zu gehen.

Ohne dass du die absoluten Grundlagen lernst, wirst du aber nicht weit kommen. Im Moment schreibst du irgendetwas irgendwohin ohne zu wissen weshalb... :roll:


Schosch - Sa 04.02.12 18:03

Also meinst du das so, oder wie??


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
procedure TForm1.FormCreate(Sender: TObject);
var PassNode :TDOMNode;
    API: TIdHttp;
    Doc: TXMLDocument;
    Internetverbindung: Boolean;

begin
  Internetverbindung:=true;
  Doc:=TXMLDocument.Create;
  API:=TIdHTTP.Create;

  try
 // API.Get('http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml');
    ReadXMLFile(Doc,API.Get('http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml'));
  except
    Internetverbindung:=false;
    Showmessage('Keine Internet-verbindung möglich');
  end;

  if Internetverbindung=true then
    begin
      PassNode := Doc.DocumentElement.FindNode('USD');
      WriteLn(PassNode.NodeValue);
      WriteLn(PassNode.FirstChild.NodeValue);
    end;
end;



Passiet aber genau dass selbe..


jaenicke - Sa 04.02.12 18:07

Dann behandle die Exception einmal richtig und schaue was es überhaupt für eine ist. Zeigt die Lazarus nicht auch an? (wie es halt bei Delphi Standard ist)

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
try
  ...
except
  on E: Exception do
    ShowMessage(E.Message);
end;
Ich habe keine Ahnung wie ReadXMLFile funktioniert und habe auch wenig Lust mich dafür mit Lazarus herumzuärgern. ;-)

// EDIT:
Vermutlich musst du wirklich den Weg über einen TMemoryStream gehen. Der zweite Parameter für ReadXMLFile ist offenbar ein Dateiname um die Daten aus einer Datei zu lesen. Das hättest du in Lazarus aber auch sehen können müssen.


Schosch - Sa 04.02.12 20:30

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:

Vermutlich musst du wirklich den Weg über einen TMemoryStream gehen. Der zweite Parameter für ReadXMLFile ist offenbar ein Dateiname um die Daten aus einer Datei zu lesen. Das hättest du in Lazarus aber auch sehen können müssen.


ja schon, aber ich hab die Datei ja gar nicht auf meinem PC. Also entwerde ich muss das machen wie ich das schon versucht habe (Direckt die informationen aus der API nehmen) oder ich muss versuchen die Datei auf meinen PC zu bekommen und diese dann einfach bei einem neuaufruf des Programmes anzupassen, und die Informationen dann von der aktualisierten Datei auszulesen. Und Beides sind Wege, die mir noch im duckeln liegen...

Also eigentlich wäre mir die zweite Variante lieber, aber da hab ich nich wirklich viel bis gar nichts zu gefunden. Was würdet ihr denn Vorschlagen welche Methonde ich anwenden soll und wie würde das gehen??


jaenicke - Sa 04.02.12 20:44

Erstell einen TMemoryStream und übergib den sowohl an Get als zweiten Parameter als auch an ReadXMLFile und fertig.


Schosch - Sa 04.02.12 20:55

Was genau ist TMemoryStream und wie erstelle ich diesen??


jaenicke - Sa 04.02.12 21:00

Mehr Informationen über Klassen und Objekte findest du hier:
http://www.delphi-treff.de/object-pascal/klassen-und-objekte/#c4939
Da findest du auch Beispiele wie du ein Objekt erzeugst. Eigentlich hast du das in deinem Quelltext aber auch schon benutzt...

Und Informationen zu TMemoryStream findest du z.B. in der Dokumentation:
http://lazarus-ccr.sourceforge.net/docs/rtl/classes/tmemorystream.html


Schosch - Sa 04.02.12 23:51

Achso, jetzt hab ich den TMemoryStrem erstellt. Wie muss ich denn jetzt die API zuweisen, ich habs mit LoadFromStream versucht, aber das will nich klappen


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
procedure TForm.Create(Sender: TObject);
Var Save: TMemoryStream;
begin
Save:=TMemoryStream.Create;

Save.LoadFromStream('http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml');

.
.
.
.
end;


aber da meinte der dann:
Unit1.pas(729,101) Error: Incompatible type for arg no. 1: Got "Constant String", expected "TStream"


jaenicke - So 05.02.12 09:41

Mach doch einfach nur was ich geschrieben habe... :roll:
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Erstell einen TMemoryStream und übergib den sowohl an Get als zweiten Parameter als auch an ReadXMLFile und fertig.
Wo steht da etwas von LoadFromStream? Nirgends.

Get kannst du als zweiten Parameter einen Stream geben, dann werden die Daten der Internetseite da hineingespeichert.


Schosch - So 05.02.12 11:33

ja versuch ich doch, nur ich hab noch nie mit ner TMemoryStream gearbeitet. Wie muss ich den Parameter denn übegeben, da muss ich dem TMemoryStream doch erstmal einen Stream übergeben, damit ich diesen an Get und ReadXMLFile übegeben kann, oder nich??


jaenicke - So 05.02.12 12:17

user profile iconSchosch hat folgendes geschrieben Zum zitierten Posting springen:
da muss ich dem TMemoryStream doch erstmal einen Stream übergeben
Äh, TMemoryStream ist wie der Name schon sagt schon ein Stream...

Du musst gar nichts weiter machen. Einfach nur den TMemoryStream als Parameter hinschreiben...

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
procedure TForm1.FormCreate(Sender: TObject);
var
  PassNode: TDOMNode;
  API: TIdHttp;
  Doc: TXMLDocument;
  PageContents: TMemoryStream;
begin
  Doc := TXMLDocument.Create;
  API := TIdHTTP.Create;
  try
    PageContents := TMemoryStream.Create;
    try
      try
        API.Get('http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml', PageContents);
        PageContents.Position := 0;
        ReadXMLFile(Doc, PageContents);
        PassNode := Doc.DocumentElement.FindNode('USD');
        WriteLn(PassNode.NodeValue);
        WriteLn(PassNode.FirstChild.NodeValue);
      except
        on E: Exception do
          Showmessage('Keine Internetverbindung möglich:'#13#10 + E.Message);
      end;
    finally
      PageContents.Free;
    end;
  finally
    API.Free;
  end;
end;
So ca. sollte es sein.

Testen kann ich es nicht, weil auch bei mir Lazarus (im virtuellen PC habe ich es auch) Indy nicht kompilieren möchte. Und so selten dämlich wie das da gemacht ist, hab ich auch keine Lust da länger herumzufummeln. :nixweiss:


Schosch - So 05.02.12 12:51

Ahhh, vielen Dank!!!

jetzt hab ich nur noch ein aller letztes Problem..
unzwar weiß ich nicht wie ich jetzt genau auf die einzelnen WechselKurse der API zugreifen kann. Um die gehts ja schließlich... Weißt du wie das geht??


jaenicke - So 05.02.12 12:59

In dem XML-Node musst du auch irgendwie die Möglichkeit haben auf die Attribute der Knoten zuzugreifen. Wie musst du mal schauen...


Schosch - So 05.02.12 13:00

Ahhh, vielen Dank!!!

jetzt hab ich nur noch ein aller letztes Problem..
unzwar weiß ich nicht wie ich jetzt genau auf die einzelnen WechselKurse der API zugreifen kann. Um die gehts ja schließlich... Weißt du wie das geht??

http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml

Ich hab das mit der Methone Textknoten einlesen versucht, die hier:

http://wiki.lazarus.freepascal.org/XML_Tutorial/de

beschrieben wird, hatte aber keinen erfolg damit. In der Zeile

Delphi-Quelltext
1:
WriteLn(PassNode.NodeValue);                    

meint der irgentwas von wegen SIGSEGV.. also ein Fehler in dem Benutzen der Klasse, aber wenn es nicht do geht wie auf der Toturial-Seite beschrieben wird, wie soll es dann sonst gehen??


jaenicke - So 05.02.12 13:02

Naja, was erwartest du denn in NodeValue? Der Knoten hat schließlich gar keinen Wert...
Außerdem ist der Knoten USD nicht direkt unter dem DocumentNode, du wirst da also vermutlich gar keinen gefunden haben. Und außerdem musst du das Attribut suchen und nicht den Namen des Knotens...

Es gibt SetAttribute, also wird es vermutlich auch GetAttribute geben. Oder vielleicht gleich Attributes oder so.


Schosch - So 05.02.12 16:01

Also wenn ich in in der Zeile

Delphi-Quelltext
1:
PassNode := Doc.DocumentElement.FindNode('USD');                    

anstadt 'USD', 'cube' eingebe, dann erkennt der auch den nächsten Befehl: WriteLn(PassNode.NodeValue); aber wie muss ich dem sagen, dass ich nur die Werte (also den Wechselkurs) eines bestimmten unterKnotens haben will...
und wie sage ich dann dass der diesen Wert in das Array "Währungen[n]" einträgt???


Schosch - Di 07.02.12 11:57

Ich hab jetzt zwei tage lang versucht auf die unterknoten in dem Knoten 'cube' zuzugreifen, aber egal was ich versucht habe es hat nicht geklappt.. Es kamen immer fehlermeldungen wie: incorect type, oder data coruption und andere... weiß denn keiner wie ich da auf die einzelnen Unterknoten zugreifen kann? ich brauche die wechsel Kurse aus der API:

http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml


jaenicke - Di 07.02.12 12:14

Ich habe drauf gewartet, dass du einmal überlegst wie du da denn wohl dran kommst. Du musst von oben nach unten jeweils den richtigen Knoten suchen und im untersten dabei das Attribut prüfen. Das ist ja eigentlich logisch, oder? Einen Quelltext in der Richtung hast du bisher nicht gepostet.

Mit XPath geht das auch in einem Rutsch über einen Abfragestring.


Schosch - Di 07.02.12 12:57

und wie benutze ich XPath?


jaenicke - Di 07.02.12 13:14

Du kannst die XPath Abfrage direkt in selectNodes bzw. selectSingleNode packen und bekommst die/den passenden Knoten zurück. ;-)

Oder du erstellst dir ein StyleSheet Dokument, in dem du dir die gewünschten Filter setzt. Dann rufst du transformNode deines Dokuments auf und übergibst dort das StyleSheet-Dokument. So kannst du direkt an den Wert kommen, der dich interessiert.


Schosch - Di 07.02.12 13:59

und wie muss ich das eingeben??
ich hab jetzt die unterpunkte von Doc... durchforstet und bin auf zwei verschieden stylesheets gestoßen, einmal StyleSheetType und StyleSheetREF. Dann habe ich das so versucht

WriteLn(Doc.StylesheetHRef);

aber mehr als versuchen kann ich nicht, weil ich mich ja auf einem total unbekannten gebiet gebiet befinde. Das heißt ich kann hier nur irgentwie die sachen eingeben was man mir vorschlägt (IDE;Forum) und gucken was passiert, aber bis jetzt is dabei halt noch nicht viel rumm gekommen.

was genau macht stylesheet, und wie muss ich das benutzen, oder nenne mir einen weg, der einfacher zu schreiben ist pls.


Horst_H - Di 07.02.12 15:18

Hallo,

Die Suche nach 'Cube' bringt eine Liste hervor, aber das ist sicher noch nicht so, wie Du es gerne hättest.
Ihc habe die XML Datei ins selbe Verzeichnis gepackt.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
program XMLSuche;
//Freepascal 2.6.0
uses 
  SysUtils,DOM,xmlread;
const 
  XMLName = 'eurofxref-daily.xml';

procedure Attribute(A:TDOMNamedNodeMap);
var
  i : longInt;
begin
   IF A = NIL then 
     begin
     writeln('No attribues');
     EXIT;
     end;

  with A do
    begin
    For i := 0 to length-1 do
      with Item[i] do
         write(NodeName+'  '+NodeValue+' ;');
    writeln;
    end;

end;

procedure SpucksAus(rootnode:TDOMNodeList);
var
  i : longint;
begin
   IF rootnode = NIL then 
     EXIT;
   with rootnode do   
     begin
     for i := 0 to (Count - 1do     
       with Item[i] do
         begin
         writeln(NodeName,'___',NodeValue); 
         Attribute(Attributes);
         SpucksAus(ChildNodes);
       end;
    end;      

end;

procedure XML_Ausgeben;
var
   Documento: TXMLDocument;
   Suche: TDOMNode;
 begin
   ReadXMLFile(Documento, IncludeTrailingPathDelimiter(GetCurrentDir)+XMLName);
    
   //Alles ausgeben 
   SpucksAus(Documento.DocumentElement.ChildNodes);
   readln;

   // Nach 'Cube' suchen 'cube' findet nichts 
   Suche := Documento.DocumentElement.FindNode('Cube');
   IF Suche <> NIL then
     SpucksAus(Suche.Childnodes)
   else
     writeln('Suche nicht erfolgreich');

   Documento.Free;

 end;
 
Begin
XML_Ausgeben; 
readln
end.

Die Ausgabe sieht so aus:

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
gesmes:subject___

#text___Reference rates   <-- Wo kommt #text als Nodename her, Typbezeichner ??
No attribues
gesmes:Sender___

gesmes:name___

#text___European Central Bank
No attribues
Cube___

Cube___
time  2012-02-06 ;
Cube___
rate  1.3042 ;currency  USD ;
Cube___
rate  99.97 ;currency  JPY ;
Cube___
usw......
Cube___
rate  40.404 ;currency  THB ;
Cube___
rate  9.9450 ;currency  ZAR ;


Suche nach Cube
Cube___
time  2012-02-06 ;
Cube___
rate  1.3042 ;currency  USD ;
Cube___
rate  99.97 ;currency  JPY ;
usw......
Cube___
rate  40.404 ;currency  THB ;
Cube___
rate  9.9450 ;currency  ZAR ;


Wie Jaenicke schon schrieb, musst Du nach 'USD' in den Attributen als NodeValue suchen.

Gruß Horst


jaenicke - Di 07.02.12 17:44

Ungetestet und nicht schön (praktisch nur vom letzten Quelltext kopiert):

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
uses
  MSXML2_TLB;

var
  API: TIdHttp;
  Doc: IXMLDOMDocument3;
  CurrencyNode: IXMLDOMNode;
begin
  Doc := CoDOMDocument60.Create;
  API := TIdHTTP.Create;
  try
    try
      Doc.loadXML(API.Get('http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml'));
      CurrencyNode := Doc.selectSingleNode('/*/*/*/*[@currency=''JPY'']');
      if Assigned(CurrencyNode) then
        ShowMessage(CurrencyNode.attributes.getNamedItem('rate').nodeValue);
    except
      on E: Exception do
        Showmessage('Keine Internetverbindung möglich:'#13#10 + E.Message);
    end;
  finally
    API.Free;
  end;
end;
So sollte es in Delphi gehen. In Lazarus sollte es ähnlich sein.


Horst_H - Di 07.02.12 20:16

Hallo,

in Freepascal gibt es die Unit xpath.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
program XMLSuche;
(*
{$SMARTLINK ON}
{$OPTIMIZATION ON}
{$OPTIMIZATION REGVAR}
{$OPTIMIZATION PEEPHOLE}
{$OPTIMIZATION CSE}
{$OPTIMIZATION ASMCSE}
*)


uses 
  classes,SysUtils,DOM,xmlread,xpath;
const 
  XMLName = 'eurofxref-daily.xml';

procedure Attribute(A:TDOMNamedNodeMap;var sl:TStringList);
var
  i : longInt;
  s : ANSIString;
begin
   IF A = NIL then 
     begin
     writeln('No attribues');
     EXIT;
     end;

  with A do
    begin
    s := '';
    For i := 0 to length-1 do
      with Item[i] do
        s:=NodeValue+'='+s;
    if s <> '' then
      begin    
      setlength(s,system.Length(S)-1 );    
      sl.Add(s);
      end;
    end;

end;

procedure SpucksAus(rootnode:TDOMNodeList;var sl: TStringList);
var
  i : longint;
begin
   IF rootnode = NIL then 
     EXIT;
   with rootnode do   
     begin
     for i := 0 to (Count - 1do     
       with Item[i] do
         begin
         Attribute(Attributes,sl);
         SpucksAus(ChildNodes,sl);
       end;
    end;      

end;

procedure XML_Ausgeben;
var
   Doc : TXMLDocument;
   rslt: TXPathVariable;
   Suche: TDOMNode;
   i :integer;
   S: TStringList;
   
 begin
   s := TStringList.create;
   ReadXMLFile(Doc, IncludeTrailingPathDelimiter(GetCurrentDir)+XMLName);
   rslt := EvaluateXPathExpression('/*/*/*/*[@currency=''JPY'']', doc.DocumentElement);

   For i := 0 to  rslt.AsNodeSet.Count-1 do
     begin
     Suche := TDomNode(rslt.AsNodeSet[i]);
     Suche := Doc.DocumentElement.FindNode(Suche.NodeName);
     IF Suche <> NIL then
       SpucksAus(Suche.Childnodes,S)
     else
       writeln('Suche nicht erfolgreich');
     end
   
   writeln(S.text);
   writeln('Ein EURO sind ',S.Values['USD'],' $');
   //Ein EURO sind 1.3042$
   writeln('Ein EURO sind ',S.Values['JPY'],' Yen');

   s.free;     
   Doc.Free;
 end;
 
Begin
XML_Ausgeben; 
readln
end.
(* Ausgabe der Stringliste
2012-02-06
USD=1.3042
JPY=99.97
BGN=1.9558
CZK=24.980
DKK=7.4342
GBP=0.82810
HUF=293.01
LTL=3.4528
LVL=0.6993
PLN=4.1770
RON=4.3420
SEK=8.8025
CHF=1.2067
NOK=7.5925
HRK=7.5830
RUB=39.4254
TRY=2.3017
AUD=1.2192
BRL=2.2549
CAD=1.3019
CNY=8.2329
HKD=10.1135
IDR=11718.28
ILS=4.8552
INR=63.9780
KRW=1463.27
MXN=16.5907
MYR=3.9374
NZD=1.5721
PHP=55.533
SGD=1.6303
THB=40.404
ZAR=9.9450

Ein EURO sind 1.3042 $
Ein EURO sind 99.97 Yen
*)


Dummerweise kommt dort nur 'Cube' zum Vorschein und nicht nur die passende Zeile:
<Cube currency='JPY' rate='99.97'/>

Das ergibt ein 600 kB Programm, wer hätte das gedacht.
Gruß Horst

EDIT ich habe die Stringliste mit Name=Value bepackt.
Ausgabe mit
writeln('Ein EURO sind ',S.Values['USD'],' $');
//Ein EURO sind 1.3042$
ist doch sehr einleuchtend.


Schosch - Mi 08.02.12 12:41

was genau macht diese Zeile???

Delphi-Quelltext
1:
CurrencyNode := Doc.selectSingleNode('/*/*/*/*[@currency=''JPY'']');                    


is das die zeile, die die einzelnen unterknoten anspricht? und wenn jaa, wie wird dann der Bereich
('/*/*/*/*[@currency=''JPY'']') definiert???

Und was genau ist das für eine Variabele(CurrencyNode')??? bzw rückgabetyp (IXMLDomNode) ???


Horst_H - Mi 08.02.12 13:28

Hallo,

ich habe da keinen blassen Schimmer, ich hab das mal schlicht von jaenicke übernommen :-), um zu schauen, ob das Beispiel von Freepascal auch hier anwendbar ist.
Gute Güte, Du kannst Dich doch über Xpath und die Abfragen dort irgendwo schlau machen.
http://de.wikipedia.org/wiki/XPath dort ist unten auch ein Tutorial angegeben. Man kann auch irgenwie zügig auf die attribute zugreifen, das ist doch sicher etwas, was Du suchst.

Gruß Horst


jaenicke - Mi 08.02.12 13:40

Da in den XML-Daten ein Namespace verwendet wird, ist es das einfachste einfach zu sagen, dass man einen Knoten in der vierten Ebene sucht, egal was für Knoten das sind, dessen Attribut currency dem wert entspricht.

Man könnte natürlich auch den Namespace deklarieren und dann direkt auf die Knoten zugreifen.

Der Variablentyp stammt aus der Windows-API. Wie das bei Lazarus aussieht, weiß ich nicht, aber das sollte in den XML-Units ja zu sehen sein. Und man kann doch sicher auch in Lazarus einfach die XML-Komponenten von MS importieren, oder?
Ich versuche gern zu helfen, aber ich habe nicht die Absicht mich deshalb mit Lazarus herumzuquälen. Da musst du schon selbst schauen. ;-)


Schosch - Fr 10.02.12 11:13

was muss ich denn machen, damit:

Delphi-Quelltext
1:
2:
uses
  MSXML2_TLB;

funktioniert? muss ich da wieder ne Komponente auf die form legen??? wenn ja welche?


jaenicke - Fr 10.02.12 11:28

Du musst die passende Typbibliothek importieren. Frag mich nicht wie das in Lazarus geht, da musst du selbst schauen. Vielleicht gibt es die entsprechende Unit auch schon. Irgendwie wird es da aber schon gehen, schließlich wäre Lazarus ja sonst Lichtjahre hinter Delphi 7, an das es sich ja anlehnt. Und viele sagen ja, dass es teilweise sogar besser sei. ;-)

In Delphi sieht das so aus (bei den Klassennamen siehst du auch die passende für das Dokument):

MsXmlImport


Schosch - Fr 10.02.12 13:58

Und was währe die passende Typ Bibliothek?? Ich will doch nur meinem Array die richtigen werte aus dem passenden unterknoten zuweisen... das kann doch nicht so kompliziert sein... du kommst immer wieder mit neuen sachen, die echt kompliziert sind (das fing an mit Indy( aber das ging ja noch), dann irgentwann kam dann mal xpath, jetzt soll ich noch ne typbibliothen einbinden, wo ich noch nichmal weiß wofür die gut ist und was die im programm macht, geschweige denn wie man die einbindet...

Es kann doch nicht so schwer sein einfach nur simple unterknoten einer online xml-datei einzulesen. Also bekannte meinerseits meinten auch dass das echt eifach sei, nur dass sie mir nich helfen könnten weil die sich halt nicht mit delphi geschweige denn lazarus aus kennen, mein lehrer kennt auch nur wirklich die prmitiven grundlagen der oop.

das heißt es kann mir hierbei echt keiner helfen, also forum arbeit. Ich bin aber noch schüler, der selber grade mal die grundlagen kennt und ihr schreibt eure info immer soo, als ob ihr vorraussetzt dass ich schon alles wüsste, wenn das der fall wäre würde ich ja nicht um hilfe fragen...

Also nocheinmal gibt es einen "relativ" simplen weg die Unterknoten einzulesen?? wenn ja dann zeigt ihn mir, wenn nicht, dann brauche ich detailierte anweisungen, sonst kann ich dass noch nicht schaffen.


Narses - Fr 10.02.12 14:14

Moin!

Leute, er ist offensichtlich überfordert, also mehr Basics, der Rest kommt später von alleine. ;)


user profile iconSchosch hat folgendes geschrieben Zum zitierten Posting springen:
Also nocheinmal gibt es einen "relativ" simplen weg die Unterknoten einzulesen?? wenn ja dann zeigt ihn mir, wenn nicht, dann brauche ich detailierte anweisungen, sonst kann ich dass noch nicht schaffen.
Probier das mal so, vielleicht kommst du damit weiter (Achtung! Das Demo-Projekt ist mit D7 erstellt!):

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
type
  TForm1 = class(TForm)
    Memo1: TMemo;
    btnGetXML: TButton;
    IdHTTP1: TIdHTTP;
    Edit1: TEdit;
    btnGetXrate: TButton;
    Edit2: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    procedure btnGetXMLClick(Sender: TObject);
    procedure btnGetXrateClick(Sender: TObject);
  end;

procedure TForm1.btnGetXMLClick(Sender: TObject);
begin
  Memo1.Text := IdHTTP1.Get('http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml');
end;

procedure TForm1.btnGetXrateClick(Sender: TObject);
  var
    i: Integer;
    XML: String;
begin
  XML := Memo1.Text;
  i := Pos(Edit1.Text, XML);
  if (i > 0then begin
    while not (XML[i] in ['0'..'9','.']) do
      Inc(i);
    Edit2.Clear;
    repeat
      Edit2.Text := Edit2.Text +XML[i];
      Inc(i);
    until not (XML[i] in ['0'..'9','.']);
  end
  else
    ShowMessage('Kurs nicht gefunden!');
end;

Screenshot

cu
Narses


Schosch - Fr 10.02.12 14:48

Ahhh, endlich mal ein quelltext mit dem auch ich was anfangen kann :D :D ich werde versuchen den noch ein wenig umzugestalten, weil ich nicht erst manuell einen knoten suchen will, sondern ihn von anfang an schon habe... aber ich glaube das müsste ich hin kriegen :D

Moderiert von user profile iconNarses: Beiträge zusammengefasst

So ich hab das jetzt mal so versucht:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
var PassNode :TDOMNode;
    API: TIdHttp;
    Doc: TXMLDocument;
    i: Integer;
    XML: String;
begin
  B_New.Click;
  Memo1.Text := IdHTTP1.Get('http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml');

  begin
  XML := Memo1.Text;
  i := Pos('USD', XML);
  if (i > 0then begin
    while not (XML[i] in ['0'..'9','.']) do
      Inc(i);
    repeat
      Waehrungen[9] := Waehrungen[9] + StrToFloat(XML+[i]);
      Inc(i);
    until not (XML[i] in ['0'..'9','.']);
  end
  //else
  //  ShowMessage('Kurs nicht gefunden!');
end;


abr jetzt sagt der mir in zeile 17, dass der operator XML nicht übergeben ist.


Narses - Fr 10.02.12 16:18

Moin!

user profile iconSchosch hat folgendes geschrieben Zum zitierten Posting springen:
Ahhh, endlich mal ein quelltext mit dem auch ich was anfangen kann
:| Tatsächlich? ;)

user profile iconSchosch hat folgendes geschrieben Zum zitierten Posting springen:
ich werde versuchen den noch ein wenig umzugestalten, weil ich nicht erst manuell einen knoten suchen will, sondern ihn von anfang an schon habe... aber ich glaube das müsste ich hin kriegen
Nun, es macht nicht den Eindruck, dass du überhaupt verstanden hast, was mein Quelltext tut. :gruebel: Vielleicht solltest du erst verstehen, was da passiert und danach umbauen. :nixweiss:

Welchen Teil des Quelltextes hast du denn nicht verstanden? :lupe:

Tipp: Wenn du meinst, du hast schon alles verstanden, dann versuche doch mal eine Funktion zu schreiben, die dir den Wechselkurs zurück liefert (als Double), wenn du das XML (als String) und die gesuchte Währung (als String) lieferst. :idea:

cu
Narses


Schosch - Sa 11.02.12 15:15

okee, ich hatte die idee, dass ich die wechselkurse in nem edit feld ausgeben lasse, und den inhalt von edit.text mit der typumwandelung strtofloat() in das array eintrage. was an sich ja kein problem ist, nur ist die ausgabe in dem editfeld keine gültige Zahl, weil das Komma als Punkt dargestellt wird und der den punkt halt nicht als komma erkennt. also muss ich befor ich die ausgabe benutzen kann den Punkt durch ein komma ersetzen. Wie muss ich das machen??

Moderiert von user profile iconNarses: Beiträge zusammengefasst

Schon gut, ich habs raus ^^ jetzt muss ich nur noch die werte aus dem editfeld nehmen :D :D endlich ist es geschafft^^

Tausend Dank nochmal, an alles die mir geholfen haben !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!