AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

RDF auslesen

Ein Thema von CalganX · begonnen am 11. Feb 2004 · letzter Beitrag vom 23. Feb 2004
Antwort Antwort
Seite 1 von 2  1 2      
CalganX

Registriert seit: 21. Jul 2002
Ort: Bonn
5.403 Beiträge
 
Turbo Delphi für Win32
 
#1

RDF auslesen

  Alt 11. Feb 2004, 19:46
Hi,
ich versuche gerade mit meinem Programm den RDF-Feed der DP (http://www.delphipraxis.com/rdf.php) auszulesen.
Die XML-Datei wird auch korrekt runtergeladen, allerdings kann ich die Items nicht auswählen und ausgeben:

Delphi-Quellcode:
procedure TfrmMain.UpdateList;
var
  sContent: string;
  i: integer;
  xmlTopics: IXMLDOMNodeList;
begin
  sContent := idhDownloader.Get(IDS_FILENAME);
  xmlDoc.loadXML(sContent);
// ShowMessage(sContent);

  if xmlDoc.parseError.errorCode <> 0 then begin
    MessageDlg('Fehler beim Laden des RDF-Feeds:'+#13#10
                  +'Die XML-Datei ist fehlerhaft! Bitte [email]chris@csd-software.net[/email] '+#13#10
                  +'kontaktieren.', mtError, [mbOK], 0);
    Close();
  end;

  xmlTopics := xmlDoc.documentElement.selectNodes('/rdf/item');
  for i := 0 to xmlTopics.length-1 do begin
    lbTopics.Items.Add(xmlTopics.item[i].selectSingleNode('title').text);
  end;
end;
Die Listbox (lbTopics) ist aber einfach leer und xmlTopics.length ist 0. Was mache ich falsch?

Chris
  Mit Zitat antworten Zitat
CalganX

Registriert seit: 21. Jul 2002
Ort: Bonn
5.403 Beiträge
 
Turbo Delphi für Win32
 
#2

Re: RDF auslesen

  Alt 13. Feb 2004, 19:03
Hi,
notgedrungen, habe ich das folgendermaßen gelöst:
Delphi-Quellcode:
procedure TfrmMain.UpdateList;
var
  sContent, sOut: string;
  i: integer;
  xmlTopics: IXMLDOMNodeList;
begin
  lbTopics.Items.Clear;
  sContent := idhDownloader.Get(IDS_FILENAME);
  xmlDoc.loadXML(sContent);

  if xmlDoc.parseError.errorCode <> 0 then begin
    MessageDlg('Fehler beim Laden des RDF-Feeds:'+#13#10
                  +'Die XML-Datei ist fehlerhaft! Bitte [email]chris@csd-software.net[/email] '+#13#10
                  +'kontaktieren.', mtError, [mbOK], 0);
    Close();
  end;

  xmlTopics := xmlDoc.documentElement.childNodes;
  for i := 2 to xmlTopics.length-1 do begin
    lbTopics.Items.Add(xmlTopics.item[i].childNodes.item[0].text);
  end;
end;
Nun versuche ich noch dazu den ensprechenden Link finden:
Delphi-Quellcode:
procedure TfrmMain.lbTopicsDblClick(Sender: TObject);
var
  sURL: string;
begin
  if lbTopics.ItemIndex = -1 then Exit;

  sURL :=xmlDoc.documentElement.selectSingleNode('item[title="'+lbTopics.Items[lbTopics.ItemIndex]+'"]').text;

  if sURL <> 'then
    ShellExecute(self.Handle, 'open', PChar(sURL), nil, nil, SW_SHOW);
end;
Allerdings erhalte ich bei dir Zuweisung von sURL eine Zugriffsverletzung. Woran liegt das? Lt. dem Feed sind die Namen der Nodes alle richtig.

Chris
  Mit Zitat antworten Zitat
MathiasSimmack
(Gast)

n/a Beiträge
 
#3

Re: RDF auslesen

  Alt 14. Feb 2004, 09:00
Dass "selectNodes" und "selectSingleNode" nicht richtig funktionieren, liegt am verwendeten Namespace
Code:
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  xmlns="http://my.netscape.com/rdf/simple/0.9/">
Das zweite Attribut wird u.a. für die "item"-Knoten verwendet. Das siehst du auch, wenn du deinen Code zum Einlesen mal modifizierst:
Delphi-Quellcode:
for i := 2 to xmlTopics.length-1 do
  ShowMessage(xmlTopics.item[i].xml);
Hier werden die "item"-Knoten nämlich so angezeigt:
Code:
<item xmlns="http://my.netscape.com/rdf/simple/0.9/">
Da das aber kein Attribut im Sinne des Wortes ist (du kannst also nicht über "getAttribute" und Co. darauf zugreifen), deklarierst du nach dem Laden des XML-Codes einfach folgendes:
Delphi-Quellcode:
xmldoc.setProperty('SelectionNamespaces',
  'xmlns:na="http://my.netscape.com/rdf/simple/0.9/"');
Wenn du mal schaust: Das unterscheidet sich nur durch das :na von der Angabe in der XML-Datei. Und genau dieses na (steht bei mir für name attribute) dient als Alias. (Du kannst stattdessen auch den Namen deiner Freundin oder was weiß ich angeben.) Zugegriffen wird dann wieder wie gehabt, wobei du den/das (?) Alias vor den gesuchten Knotennamen stellst:
Delphi-Quellcode:
xmlTopics := xmldoc.selectNodes('//na:item/na:title');
if(xmlTopics.length > 0) then
  for i := 0 to xmlTopics.length - 1 do
    lbTopics.Items.Add(xmlTopics.item[i].text);
Die Angabe des Alias ist, wie gesagt!, erforderlich, weil die Knoten sonst nicht gefunden werden.

Dein Problem mit der Zugriffsverletzung bei der URL lässt sich auf ähnliche Art lösen, wobei ich aber vorschlagen möchte, dass du in jedem Fall den Umweg über einen Knoten (IXMLDOMNode) nimmst. Momentan entsteht die Zugriffsverletzung nämlich, weil "selectSingleNode" (auf Grund des Namespace) nichts findet, und du versuchst nun den Text eines nicht gefundenen Knotens an eine Variable zu übergeben.
Das kann aber auch passieren, wenn du im Editor bspw. einen Knoten aus der XML-Datei entfernst und vergessen hast, dass das Programm noch eine zuvor geladene, vollständige Version des Dokumentes benutzt.

Daher würde ich das also so machen:
Delphi-Quellcode:
node := xmldoc.selectSingleNode('//na:item[na:title="' +
  lbTopics.Items[lbTopics.ItemIndex] + '"]/na:link');

if(node <> nil) then
begin
  sUrl := node.text;
  ShellExecute(self.Handle,'open',pchar(sUrl),nil,nil,SW_SHOWNORMAL);
end;
(falls erforderlich musst du vorher wieder die Namespace-Eigenschaft setzen!)
  Mit Zitat antworten Zitat
CalganX

Registriert seit: 21. Jul 2002
Ort: Bonn
5.403 Beiträge
 
Turbo Delphi für Win32
 
#4

Re: RDF auslesen

  Alt 14. Feb 2004, 09:03
Hi Mathias,
danke für deine Erklärung. Ich werde das nachher mal ausprobieren und dann werde ich dir sagen können, ob es funktioniert.

Chris
*frühstücken geh*
  Mit Zitat antworten Zitat
CalganX

Registriert seit: 21. Jul 2002
Ort: Bonn
5.403 Beiträge
 
Turbo Delphi für Win32
 
#5

Re: RDF auslesen

  Alt 14. Feb 2004, 09:36
Hi nochmal,
also: hat wunderbar funktioniert. Vielen Dank. Gibt es eine Möglichkeit mit XML herauszufinden, welcher dieser Namepsaces gesetzt ist bzw. werden muss?

Chris
  Mit Zitat antworten Zitat
MathiasSimmack
(Gast)

n/a Beiträge
 
#6

Re: RDF auslesen

  Alt 14. Feb 2004, 09:59
Gute Frage. Auslesen kannst du sie (zumindest die URLs) über IXMLDOMSchemaCollection (s. PSDK), bzw. auf die Schnelle:
Delphi-Quellcode:
sch := xmldoc.Get_namespaces;
if(sch.length > 0) then
  for i := 0 to sch.length - 1 do
    ShowMessage(sch.namespaceURI[i]);
Aber wie man sie jetzt so zuweist, dass man damit die entsprechenden Knoten findet ... ... da muss ich mich selbst erst mal damit beschäftigen. Oder wir fragen einfach mal sakura, bzw. einen anderen XML-Profi.
  Mit Zitat antworten Zitat
Benutzerbild von Jens Schumann
Jens Schumann

Registriert seit: 27. Apr 2003
Ort: Bad Honnef
1.644 Beiträge
 
Delphi 2009 Professional
 
#7

Re: RDF auslesen

  Alt 14. Feb 2004, 12:06
Hallo,
ich habe mich wegen dieses Threads zum ersten mal mit XMlDocument beschäftigt.
Deshalb habe ich mir die Typebibliothek der Verion 5 (kam mit Office 2003) importiert
(mit Komponentenwrapper deshalb steht im Sourc immer DefaultInterface).
Damit habe ich dann versucht das Beispiel nachzuvollziehen. Hat auch geklappt.
Delphi-Quellcode:
unit xml_main_frm;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, MSXML5_TLB, StdCtrls, OleServer;

type
  TForm1 = class(TForm)
    Button1: TButton;
    ListBox1: TListBox;
    XMLDoc: TMSDOMDocument50;
    procedure Button1Click(Sender: TObject);
    procedure XMLDocondataavailable(Sender: TObject);
  private
    { Private-Deklarationen }
    procedure LoadXML_List(const Source : String);
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  ListBox1.Clear;
  LoadXML_List('http://www.delphipraxis.com/rdf.php');
end;

procedure TForm1.LoadXML_List(const Source: String);
begin
  XMLDoc.DefaultInterface.load(Source);
end;

procedure TForm1.XMLDocondataavailable(Sender: TObject);
var
  xmlTopics : IXMLDOMNodeList;
  iCnt : Integer;
  jCnt : Integer;
begin
  If XMLDoc.DefaultInterface.parseerror.errorCode=0 then
    begin
// XMLDoc.DefaultInterface.SetProperty('SelectionNamespaces','xmlns:na="http://my.netscape.com/rdf/simple/0.9/"');

    xmlTopics := xmlDoc.DefaultInterface.documentElement.childNodes;
    For iCnt := 0 to xmlTopics.length-1 do
      begin
      For jCnt:=0 to xmlTopics.item[iCnt].childNodes.length-1 do
        ListBox1.Items.Add(xmlTopics.item[iCnt].childNodes.item[jCnt].Text+' : '+
        xmlTopics.item[iCnt].childNodes.item[jCnt].nodeName);
      ListBox1.Items.Add('----');
      end;
    end
      else
        ShowMessage('Fehler beim parsen');
end;

end.
Bei mir funktioniert es auch ohneXMLDoc.DefaultInterface.SetProperty('SelectionNamespaces','xmlns:na="http://my.netscape.com/rdf/simple/0.9/"'); D.h. mit XMLDoc.DefaultInterface.SetProperty('SelectionNamespaces','xmlns:na="http://my.netscape.com/rdf/simple/0.9/"'); funktioniert es bei mir nicht. Sonderbar ???
  Mit Zitat antworten Zitat
CalganX

Registriert seit: 21. Jul 2002
Ort: Bonn
5.403 Beiträge
 
Turbo Delphi für Win32
 
#8

Re: RDF auslesen

  Alt 14. Feb 2004, 12:27
Hi,
nein denke ich nicht, weil es XML 5.0 ist. Ich denke, dass MSXML5 sich diese Daten selber herauszufinden versucht. Aber sicher bin ich mir nicht.

Chris
  Mit Zitat antworten Zitat
MathiasSimmack
(Gast)

n/a Beiträge
 
#9

Re: RDF auslesen

  Alt 14. Feb 2004, 14:59
@Jens: Das, was du hier machst
Delphi-Quellcode:
xmlTopics := xmlDoc.DefaultInterface.documentElement.childNodes;
For iCnt := 0 to xmlTopics.length-1 do
  { ... }
entspricht meiner Ansicht nach der Idee, die Chris am Anfang hatte. Du gehst damit zwar dem Namespace-Problem aus dem Weg und kannst (wenn du es eingrenzt) alle "item"-Knoten bzw. alle "title" auslesen, aber dazu musst du eben alles selbst durchlaufen.

Einer der Vorteile, die bspw. der MS-XML-Parser bietet (nicht nur der, denke ich!), ist aber XPath. Das heißt, du kannst angeben, welche Bedingungen erfüllt sein müssen, und dann erhältst du eine Liste mit allen gefundenen Knoten, die diesen Bedingungen entsprechen. Vielleicht könnte man das (wenn man es nicht allzu wörtlich nimmt) mit dem SELECT-Statement von mySQL vergleichen?!

Im Prinzip macht diese Anweisung:
Delphi-Quellcode:
xmlTopics := xmldoc.selectNodes('//item/title');
if(xmlTopics.length > 0) then
  for i := 0 to xmlTopics.length - 1 do
    lbTopics.Items.Add(xmlTopics.item[i].text);
das gleiche wie
Delphi-Quellcode:
xmlTopics := xmldoc.documentElement.childNodes;
if(xmlTopics.length > 0) then
  for i := 0 to xmlTopics.length - 1 do
    if(xmlTopics.item[i].Get_nodeName = 'item') then
      lbTopics.Items.Add(xmlTopics.item[i].childNodes.item[0].text);
wobei die zweite Variante einen Schönheitsfehler hat: ohne Prüfung wird grundsätzlich der erste Unterknoten benutzt
xmlTopics[i].childNodes.item[0] in der Hoffnung, dass dieser der "title" ist. Normalerweise müsste man also noch prüfen, ob das auch zutrifft, und erst dann könnte/dürfte man die ermittelte Beschreibung in die Listbox eintragen.

Da ist der Weg mit XPath doch weitaus kürzer, weil bei ihm sofort die "title"-Knoten ermittelt werden, die sich unter einem "item"-Knoten befinden.

Oder nimm den Teil, bei dem die URL ermittelt werden soll. Als Referenz (zum Vergleich) dient der Titel (= die Beschreibung) aus der Listbox. Mit einer Schleife müsstest du also wieder durch alle Knoten durch, schauen ob es ein "item"-Knoten ist, prüfen ob der einen untergeordneten "title"-Knoten hat, vergleichen ob dessen Textinhalt mit dem selektierten Eintrag der Listbox identisch ist, und dann zu guter Letzt den "link"-Knoten und damit die URL ermitteln. Bei XPath genügt ein simples:
Delphi-Quellcode:
node := xmldoc.selectSingleNode('//item[title="' +
  lbTopics.Items[lbTopics.ItemIndex] +
  '"]/link');

if(node <> nil) then
  ShowMessage(node.text);
und du hast die URL.

Ein bisschen merkwürdig wird es in diesem speziellen Fall eben nur durch den Namespace. Im PSDK heißt es:
SelectionNamespaces Property (Remarks)
When an XML document contains elements defined in an external namespace, you must use this property to specify that namespace in order to use DOM methods such as selectNodes or selectSingleNode to navigate the document.


@all: Ich habe durch wildes Herumprobieren folgende Variante, die unabhängig vom Namespace trotzdem alle Titel ausliest:
xmlTopics := xmldoc.selectNodes('//*[name(.)="item"]/*[name(.)="title"]'); Etwas ... *hüstel* ... extrem wird´s beim Versuch, die URL zu ermitteln.
Delphi-Quellcode:
node := xmldoc.selectSingleNode(
  { alle Knoten namens "item" }
  '//*[name(.)="item"]/' +
  { alle Unterknoten namens "text", deren Text
    mit dem Listbox-Eintrag identisch ist }

  '*[name(.)="title" and text()="' + lbTopics.Items[lbTopics.ItemIndex] + '"]' +
  { dann eine Ebene nach oben und alle (hoffentlich nur einen!)
    Knoten namens "link" }

  '/../*[name(.)="link"]');

if(node <> nil) then
  ShowMessage(node.text);


Ich bezweifle, dass das eine vernünftige Variante ist. Dann sollte man sich wohl lieber mit dem Namespace auseinander setzen. Aber es funktioniert ... irgendwie ...
  Mit Zitat antworten Zitat
Benutzerbild von Jens Schumann
Jens Schumann

Registriert seit: 27. Apr 2003
Ort: Bad Honnef
1.644 Beiträge
 
Delphi 2009 Professional
 
#10

Re: RDF auslesen

  Alt 14. Feb 2004, 15:12
@Matthias
XMLDoc.DefaultInterface.SetProperty('SelectionNamespaces','xmlns:na="http://my.netscape.com/rdf/simple/0.9/"'); verursacht bei mir eine stille Exception (wie auch immer das an dieser Stelle funktioniert). D.h. man merkt erst, das in der Zeile eine Exception auftritt, wenn man den Source in einen Try/Except Block kapselt.
Mit folgendem Source:
Delphi-Quellcode:
procedure TForm1.XMLDocondataavailable(Sender: TObject);
var
  xmlTopics : IXMLDOMNodeList;
  iCnt : Integer;
  jCnt : Integer;
begin
  If XMLDoc.DefaultInterface.parseerror.errorCode=0 then
    begin
    Try
      XMLDoc.DefaultInterface.SetProperty('SelectionNamespaces','xmlns:na="http://my.netscape.com/rdf/simple/0.9/"');

      xmlTopics := xmlDoc.DefaultInterface.documentElement.childNodes;
      For iCnt := 0 to xmlTopics.length-1 do
        begin
        For jCnt:=0 to xmlTopics.item[iCnt].childNodes.length-1 do
          ListBox1.Items.Add(xmlTopics.item[iCnt].childNodes.item[jCnt].Text+' : '+
          xmlTopics.item[iCnt].childNodes.item[jCnt].nodeName);
        ListBox1.Items.Add('----');
        end;
      XMLDoc.DefaultInterface.save(ApplicationPath+'Test.xml');
    Except
      On E : Exception do
        ShowMEssage(E.Message);
        end;
    end
      else
        begin
        ListBox1.Items.Add('Errorcode: '+IntToStr(XMLDoc.DefaultInterface.parseerror.errorCode));
        ListBox1.Items.Add('Line: '+IntToStr(XMLDoc.DefaultInterface.parseerror.Line));
        ListBox1.Items.Add('Char: '+IntToStr(XMLDoc.DefaultInterface.parseerror.LinePos));
        ListBox1.Items.Add('Descritpion: '+(XMLDoc.DefaultInterface.parseerror.Reason));
        end;
end;
erhalte ich folgende Fehlermeldung:Versuch, einen schreibgeschützten Knoten zu ändern

Lustigerweise zweimal hintereinander
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:14 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz