AGB  ·  Datenschutz  ·  Impressum  







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

XML Find Node with Attribute

Ein Thema von aegidos · begonnen am 19. Mär 2010 · letzter Beitrag vom 20. Mär 2010
Antwort Antwort
aegidos

Registriert seit: 30. Okt 2007
40 Beiträge
 
Delphi 2007 Professional
 
#1

XML Find Node with Attribute

  Alt 19. Mär 2010, 14:40
Hallo,
Ich hab das Forum nun schon rauf und runter durchsucht, irgendwie trete ich bei folgendem Problem auf der Stelle:

Ich habe eine XML Datei:
<datagrid /> Dieser XML Datei möchte ich Knoten einhängen. Die Knoten heißen immer <data></data> und unterscheiden sich nur durch ein Attribut und den Wert.

Beispielsweise :
<data cname="b_Downloadfile">C:\Software\binary.bin</data>

Ich muss eine Hashtabelle durchlaufen welche zu jedem Namen auch einen Wert enthält. Ist eine Tabelle mit 2 Spalten in denen sich korrespondierende Paare befinden:
b_Downloadfile <--->C:\Software\binary.bin
c_Downloadfile <--->D:\Software\binary001.bin
Wenn meine XML Datei noch leer ist, dann ist es relativ einfach da ich über addchild einfach ein Daten-Node erzeuge und die Werte zuweise. Wo ich nicht ganz durchsteige wie ich abprüfe ob es den entsprechenden Node nicht schon in meiner XML gibt. weil dann will ich ihn nicht neu einfügen sondern den Wert überschreiben.

Mein Fortschritt bis dato:
Delphi-Quellcode:
procedure TLogDlg.SaveStringGrid( const FileName: TFileName);
var
  f: TextFile;
  i, k,l: Integer;
  tagFound: Integer;
  xmlTag : String;
  XMLDocumentDataGrid: TXMLDocument;
  newNode: IXMLNode;
begin
  l := 0;
  tagFound := 0;
  if FileExists(FileName)then
  begin

  XMLDocumentDataGrid := TXMLDocument.Create(Application);
  XMLDocumentDataGrid.FileName := FileName;
  XMLDocumentDataGrid.Active := true;

    // loop through cells -- Hashtabelle mit korrespondierenden Wertepaaren
    for i := 0 to LogDlg.dataGrid.RowCount - 1 do
      for k := 0 to LogDlg.dataGrid.ColCount - 1 do
      begin
        if (LogDlg.dataGrid.Cells[k, i] <> '')and (LogDlg.dataGrid.Cells[k+1, i] <> '') then
        begin
//in xmlTag steht der Wert den das Attribut cname dann bekommen soll
           xmlTag := StringReplace(LogDlg.dataGrid.Cells[k, i], ' ', '', [rfReplaceAll, rfIgnoreCase]);
            newNode:=XMLDocumentDataGrid.DocumentElement.ChildNodes.FindNode('data');
           while( newNode <> nil )do
           begin
           //data knoten schon vorhanden
                if(newNode.Attributes['cname'] = xmlTag)then
                begin
//hier habe ich bedenken denn eigentlich will ich ja den Wert in XMLDocumentDataGrid setzen und nicht in newNode .... liegt hier das Problem?
                          newNode.Text:=LogDlg.dataGrid.Cells[k+1, i];
                          tagFound := 1;
                          Break;
                end else begin
                        newNode := newNode.NextSibling;
                end;
           end;


        end;

      end;
       if (tagFound=0) then begin
             //no tag was found
             (XMLDocumentDataGrid.DocumentElement.AddChild('data').Attributes['cname']:=xmlTag);
//hier müsste ich nun noch dem eben hinzugefügten Knoten einen Wert hinzuweisen. Leider kann ich nicht alles in Klammern setzen und .Text beschreiben, wie geht denn das?
             XMLDocumentDataGrid.SaveToFile(FileName);
             XMLDocumentDataGrid.Active := False;
              SaveStringGrid(FileName);
           end else
           begin
                   XMLDocumentDataGrid.SaveToFile(FileName);
                   XMLDocumentDataGrid.Active := False;
           end;


  end;
end;
ABer irgendwie steht da immer nur das letzte korrespondierende Wertpaar drinnen wenn ich die XML Datei dann öffne.
was mir fehlt ist ein Befehl find Node with Name and Attribute Value
XMLDocumentDataGrid.DocumentElement.ChildNodes.FindNode('data').Attributes['cname'==xmlTag].Text :=LogDlg.dataGrid.Cells[k+1, i]; Hat hier jemand eine Idee?
Wenn ich XPath verwende dann kann ich das mit INodeXml nicht machen oder?
So ähnlich, nur ohne das .Value
//data[starts-with(@cname,xmlTag)].Value

Danke und schöne Grüße
Andi
  Mit Zitat antworten Zitat
Benutzerbild von sx2008
sx2008

Registriert seit: 15. Feb 2008
Ort: Baden-Württemberg
2.332 Beiträge
 
Delphi 2007 Professional
 
#2

Re: XML Find Node with Attribute

  Alt 19. Mär 2010, 21:31
Du könntest das mit XPath lösen.
Mit XPath kann man wie mit einem Filter einen oder mehrere Knoten aus der Gesamtmenge rausholen.
Beispiele für XPath-Ausdrücke:
liefert alle Elemente namens "data", die das Attribut "cname" haben
Code:
//data[@cname]
liefert alle Elemente namens "data", bei denen das Attribut "cname" den Wert 123 hat.
Code:
//data[@cname="123"]
Viele Parser haben XPath-Unterstützung. Die genaue Syntax ist von Parser abhängig.
Delphi-Quellcode:
// Knoten mit XPath selektieren
nodelist := rootelement.SelectNodes('//data[@cname="123"]');
for i := 0 to nodelist.count-1 do // über alle Knoten
begin
  node := nodelist.Item[i];
  // z.B. wird hier ein neues Attribut gesetzt
  (node as IXMLElement).SetAttribute('idx', inttoStr(i));
end;
  Mit Zitat antworten Zitat
aegidos

Registriert seit: 30. Okt 2007
40 Beiträge
 
Delphi 2007 Professional
 
#3

Re: XML Find Node with Attribute

  Alt 20. Mär 2010, 16:30
Hallo sx2008,
Danke für die schnelle Antwort.

Dann versuche ich mal mein Glück mit SelectNodes.
Eine Frage habe ich noch zu deinem Code:
Delphi-Quellcode:
// Knoten mit XPath selektieren
//hier wird doch eine KOPIE von rootelement."KnotenUnterMenge" angelegt oder?
nodelist := rootelement.SelectNodes('//data[@cname="123"]');
for i := 0 to nodelist.count-1 do // über alle Knoten
begin
  node := nodelist.Item[i];

//hier fügst du in node ein neues Attribut ein, wenn ich nun weiter unten
//XMLDocumentDataGrid.SaveToFile(FileName); mache dann ist dort mein eingefügtes
//Attribut nicht eingefügt oder?
  (node as IXMLElement).SetAttribute('idx', inttoStr(i));
end;
Muss ich dann vielleicht so vorgehen:
rootelement.SelectNodes('//data[@cname="123"]').SetAttribute('idx', inttoStr(i)); Aber geht das SetAttribute überhaupt anschließend an Select Nodes, weil es handelt sich ja um eine Nodelist und keinen einzelnen Node!??
Wenns den Knoten gibt füge ich einen aktuellen Wert als Attribut ein und wenns den Knoten nicht gibt erzeuge Ich ihn neu.
Klingt gar nicht so kompliziert muss ich mal testen und melde mich dann wieder.

Schöne Grüße
Andreas
  Mit Zitat antworten Zitat
aegidos

Registriert seit: 30. Okt 2007
40 Beiträge
 
Delphi 2007 Professional
 
#4

Re: XML Find Node with Attribute

  Alt 20. Mär 2010, 20:32
Hallo,
Also dass scheint doch mega advanced zu sein zumindest für mich. Nachdem ich mir ein paar Tutorials reingezogen hab (Teilweise sind die recht alt von 2003) bin ich immer noch nicht weitergekommen.
Das SelectSingleNode kann ich nicht ausführen da ich mir kein
xmlDoc: IXMLDOMDocument2; anlegen kann, was wiederum daran liegt, dass meine uses directive die UNITS msxml2 oder MSXML2_TLB nicht akzeptiert.

Von welchem Typ müsste denn rootelement sein?
Um einfach meine schon implementierten IXMLNode zu benutzen habe ich mir hier aus dem Forum eine unit geholt:
ForumXML
von Midiar für OpenXML adomxmldom.pas geschrieben.

Meine jetzt "verbesserte" Funktion stürtzt schon beim Laden des XML Files ab. Das Hatte mit TXML noch ganz gut funktioniert, aber dafür gibt es ja kein SelectSingleNode.

VORHER
Delphi-Quellcode:
  XMLDocumentDataGrid := TXMLDocument.Create(Application);
  XMLDocumentDataGrid.FileName := FileName;
  XMLDocumentDataGrid.Active := true;
NACHHER
Delphi-Quellcode:
procedure TForm1.SaveStringGrid( const FileName: TFileName);
var
  f: TextFile;
  i, k,l: Integer;
  tagFound: Integer;
  xmlTag,destFile : String;
  XMLDocumentDataGrid: IXMLDOMDocument;
  newNode,rootelement: IXMLNode;
  eintraege: IXMLDOMNodeList;
    subNode,node: IXMLDOMNode;
  xmlDoc: IXMLDOMDocument;


  nodelist: IXMLNodeList;
begin
  l := 0;
  tagFound := 0;
  if FileExists(FileName)then
  begin
//hier kommt schon der erste CRASH
  XMLDocumentDataGrid.loadXML(FileName) ;


    // loop through cells -- Hashtabelle mit korrespondierenden Wertepaaren
    for i := 0 to LogDlg.dataGrid.RowCount - 1 do
      for k := 0 to LogDlg.dataGrid.ColCount - 1 do
      begin
        if (LogDlg.dataGrid.Cells[k, i] <> '')and (LogDlg.dataGrid.Cells[k+1, i] <> '') then
        begin
        //in xmlTag steht der Wert den das Attribut cname dann bekommen soll
           xmlTag := StringReplace(LogDlg.dataGrid.Cells[k, i], ' ', '', [rfReplaceAll, rfIgnoreCase]);
         // Knoten mit XPath selektieren
         eintraege := XMLDocumentDataGrid.selectNodes('werte/eintrag/grenzwert[@benutzt="ja"]');


          node := XMLDocumentDataGrid.DocumentElement.selectSingleNode('//data[@cname=xmlTag]');
          if(node<>nil)then begin
            (node as IXMLNode).Text:=LogDlg.dataGrid.Cells[k+1, i];

          end else begin
             // XMLDocumentDataGrid.DocumentElement.appendChild(subNode).attributes['cname']:=xmlTag;
          node := XMLDocumentDataGrid.DocumentElement.selectSingleNode('//data[@cname=xmlTag]');
              node.Text:=LogDlg.dataGrid.Cells[k+1, i];
          end;

        end;

      end;
             XMLDocumentDataGrid.save(FileName);
// XMLDocumentDataGrid.Active := False;
  end;
end;
Was mach ich denn nur falsch?
Danke und schöne Grüße
Andi
  Mit Zitat antworten Zitat
Antwort Antwort


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 22:57 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