Results 1 to 8 of 8

Thread: XML dubbelen verwijderen

  1. #1

    Question XML dubbelen verwijderen

    Hi,

    ik ben bezig met een opschoon tooltje voor xml bestanden. Het gaat erom dat de dubbelen verwijderd worden. De structuur is zoiets als:

    Code:
    <?xml version="1.0" encoding="utf-8"?>
    <gpx>
    	<wpt lat="51.036567" lon="5.8439">
    		<name>punt 1</name>
    	</wpt>
    	<wpt lat="51.063383" lon="5.86045">
    		<name>punt 2</name>
    	</wpt>
    	<wpt lat="53.1913" lon="-6.0803">
    		<name>punt 3</name>
    	</wpt>
            <wpt lat="51.036567" lon="5.8439">
    		<name>punt 1</name>
    	</wpt>
    
    	<wpt lat="52.152433" lon="5.2932">
    		<name>punt 4</name>
    	</wpt>
    	<wpt lat="50.20635" lon="7.3335">
    		<name>punt 5</name>
    	</wpt>
            <wpt lat="51.036567" lon="5.8439">
    		<name>punt 1</name>
    	</wpt>
    
    </gpx>
    In dit voorbeeld komt "punt 1" dus drie keer voor. De parentnode (wpt) komt ook drie keer voor met dezelfde attributen.

    Ik gebruik IXmlDocument en IXmlNode en probeer door te loopen door de XML de dubbelen te verwijderen, maar het lukt me niet. Kan er iemand een simpel voorbeeldje geven hoe dit te doen?

    Alvast bedankt!

  2. #2
    Dit doet wat het moet doen, of het snel en efficient is is de vraag. Maar het werkt

    Code:
      procedure RemoveDuplicates;
      var
        xml: string;
        list: TStringList;
        i: Integer;
      begin
        list := TStringList.Create;
        try
          for i := pred(NewGpxXml.DocumentElement.ChildNodes.Count) downto 0 do
          begin
            xml := NewGpxXml.DocumentElement.ChildNodes.Nodes[i].XML;
            if List.IndexOf(xml) > -1 then
            begin
                NewGpxXml.DocumentElement.ChildNodes.Delete(i);
            end
            else
            begin
                List.Add(xml);
            end;
          end;
        finally
          FreeAndNil(list);
        end;
    
      end;

  3. #3
    Gaat het puur om deze xml? Dus wil je alleen rekening houden met dit schema?
    Als dat het geval is lijkt het me het makkelijkst om de xml te importeren in Delphi en er een unit van te laten genereren.
    Dan de XML doorlopen van elke node zelf een object maken deze met elkaar te vergelijken en eventuele duplicaten te verwijderen.
    Van het restant kan je dan een nieuw bestand opbouwen met behulp van de geïmporteerde classes.

  4. #4
    Heb even verder gespeeld, let op dit antwoord werkt alleen voor de xml die je hebt opgegeven.
    Natuurlijk kunnen er meer/minder/andere gegevens in staan maar de structuur van het bestand is wel van belang.
    Ik heb de xml geïmporteerd in Delphi en ben daarmee aan de slag gegaan.

    DISCLAIMER: Ik weet niet of dit de beste manier is. Het is in ieder geval een manier.

    Code:
    type
      TWayPoint = class
      private
        FName: string;
        FLat: Extended;
        FLon: Extended;
      public
        constructor Create(ANode: IXMLWptType);
        property Name: string read FName write FName;
        property Lat: Extended read FLat write FLat;
        property Lon: Extended read FLon write FLon;
      end;
    
      TMyList = class(TObjectList<TWayPoint>)
      public
        function WaypointExists(APoint: TWayPoint): boolean;
      end;
    
      TForm1 = class(TForm)
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
        procedure FormCreate(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
      FSettings: TFormatSettings;
    In de formcreate moet je even de decimalseperator zetten in FSettings.
    Code:
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      FSettings.DecimalSeparator := '.';
    end;
    Create van TWaypoint
    HTML Code:
    constructor TWayPoint.Create(ANode: IXMLWptType);
    begin
      FName := ANode.Name;
      FLat := Extended.Parse(Anode.Lat, FSettings);
      FLon := Extended.Parse(Anode.Lon, FSettings);
    end;
    Bekijken of je waypoint al in de lijst voor komt
    Code:
    function TMyList.WaypointExists(APoint: TWayPoint): boolean;
    var
      LPoint: TWayPoint;
    begin
      Result := False;
      for LPoint in Self do
        if (LPoint.Name = APoint.Name) and (LPoint.Lat = APoint.Lat) and
           (LPoint.Lon = APoint.Lon) then
          Exit(True)
    end;
    De xml laden, verwerken, en opnieuw opslaan zit in de buttonclick
    Code:
    procedure TForm1.Button1Click(Sender: TObject);
    var
      LFile,
      LResult: IXMLGpxType;
      I: integer;
      LWP: TWayPoint;
      LList: TMyList;
      LNode: IXMLWptType;
    begin
      LList := TMyList.Create;
      try
        //xml laden, functie zit in de gegenereerde unit door xml import
        LFile := Loadgpx('<Pad naar je xml bestand>');
        for I := 0 to LFile.Count-1 do
        begin
          LWP := TWayPoint.Create(LFile[I]);
          //Alleen toevoegen als waypoint nog niet bestaat
          if not LList.WaypointExists(LWP) then
            LList.Add(LWP);
        end;
        //Nieuw leeg bestand. Ook beschikbaar door xml import
        LResult := Newgpx;
        for LWP in LList do
        begin
          //Node maken en vullen met data
          LNode := LResult.Add;
          LNode.Name := LWP.Name;
          LNode.Lat := LWP.Lat.ToString(FSettings);
          LNode.Lon := LWP.Lon.ToString(FSettings);
        end;
        //Nieuwe bestand opslaan
        LResult.OwnerDocument.SaveToFile('<Nieuwe locatie>');
      finally
        LList.Free;
      end;
    end;
    Hopelijk heb je er iets aan

  5. #5
    Fornicatorus Formicidae VideoRipper's Avatar
    Join Date
    Mar 2005
    Location
    Vicus Saltus Orientalem
    Posts
    5,274
    Quote Originally Posted by crownie View Post
    DISCLAIMER: Ik weet niet of dit de beste manier is. Het is in ieder geval een manier.
    Noot: als je een niet te oude versie van Delphi hebt (vanwege oa generics).
    TMemoryLeak.Create(Nil);

  6. #6
    Quote Originally Posted by VideoRipper View Post
    Noot: als je een niet te oude versie van Delphi hebt (vanwege oa generics).
    Correct.
    Ik weet niet wat er dan allemaal weg valt maar de TObjectList zou je kunnen vervangen door een TList, alleen moet je dan wel steeds je objecten typecasten.

    @Creuwels welke Delphi versie gebruik je?

  7. #7
    Fornicatorus Formicidae VideoRipper's Avatar
    Join Date
    Mar 2005
    Location
    Vicus Saltus Orientalem
    Posts
    5,274
    Als je een TList gebruikt moet je zelf de objecten erin opruimen.
    Een TObjectList zal niet zozeer het probleem zijn, deze bestaat al sinds 1670 ofzo, maar
    zoals hij hier gebruikt wordt (als een generic list) werkt hij niet onder D2007 en lager.
    Je zult dan de Items-property/GetItem-functie moeten overriden zodat er een TWayPoint
    uitkomt (of inderdaad typecasten).

    Ook de .ToString-functies werken bij oudere Delphi-versies overigens niet.
    TMemoryLeak.Create(Nil);

  8. #8
    Ah ok. Ik werk zelf nu iets langer dan 5 jaar met Delphi en heb de luxe dat we op werk een subscription hebben en dus bijna altijd met de nieuwste versie werken.
    Zelf denk ik dus niet zo snel aan oudere versies :P

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •