-3

Here is my Xml

<Cars>
<Car id="1" name="Opel" picture="\File\JPEG\opel.jpg" />
<Car id="2" name="Ford" picture="\File\JPEG\ford.jpg"  />
<Car id="3" name="Volvo" picture="\File\JPEG\volvo.jpg" />
</Cars>

Now I want to add new cars

Listbox1     Listbox2 
(CarName)   (Car.Picture)
 BMW        \File\JPEG\bmw.jpg
Mercedes    \File\JPEG\Merdedes.jpg

Problem I have with car.Id. Each id must be unique (+1) Having already 3 cars in the file how to make every other car id +1

My code

    var
    lNewCar: IXMLCarType;
      i, NewID : Integer;
      begin
      i:= 0;
      NewID := 1 + MaxID (Form1.Memo1.Lines.Text);
      while ( i < ListBox1.Count) and  ( i < ListBox2.Count) 
      begin
        lNewCar := XMLIntf.Cars.add;
        lNewCar.id   := NewID;
        lNewCar.name := Listbox1.Items[i];
        lNewCar.jpeg := Listbox2.Items[i];
       Inc(i);
      end;
    end;
Maryna98
  • 1
  • 3
  • Why don't you just find the highest existing ID (e.g. using an XPath query on the XML) and then just add 1 to it? – MartynA May 17 '17 at 16:51
  • Because I do not know.Can you give an example? – Maryna98 May 17 '17 at 17:33
  • See my answer I've just posted. – MartynA May 17 '17 at 17:36
  • Btw, your edit to include my code has completely changed what you are asking about. You should revert your q t how it was before that edit, and then post a new q about the AV. But before you do that, see stackoverflow.com/help/mcve because your new q will need to include an MCVE - and note the "Complete" in "MCVE" – MartynA May 17 '17 at 19:42

1 Answers1

2

In view of the simple structure of your XML, just a series of Car nodes below a Cars root node, you can find the maximum existing id attribute value by iterating the Car nodes and examining their id attributes, like this:

Sample project:

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    btnMaxId: TButton;
    procedure btnMaxIdClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  public
  end;

function MaxId(const XML : String) : Integer;
[...]
var
  Form1: TForm1;
implementation
[...]
procedure TForm1.btnMaxIdClick(Sender: TObject);
begin
  ShowMessage(IntToStr(MaxID(Memo1.Lines.Text)));
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.Lines.Add('<Cars>');
  Memo1.Lines.Add('  <Car id="1" name="Opel" picture="\File\JPEG\opel.jpg" />');
  Memo1.Lines.Add('  <Car id="98" name="Ford" picture="\File\JPEG\ford.jpg"  />');
  Memo1.Lines.Add('  <Car id="3" name="Volvo" picture="\File\JPEG\volvo.jpg" />');
  Memo1.Lines.Add('</Cars>');
end;

function MaxId(const XML : String) : Integer;
var
  XmlDoc: IXMLDOMDocument;
  NodeList : IXmlDOMNodeList;
  Node : IXMLDomNode;
  i : Integer;
  ID : Integer;
  ErrorCode : Integer;
  S : String;
begin
  Result := 0;
  XmlDoc := CoDOMDocument.Create;
  try
    XmlDoc.Async := False;
    XmlDoc.LoadXml(XML);

    NodeList := XmlDoc.DocumentElement.childNodes;
    for i := 0 to NodeList.Length - 1 do begin
      Node := NodeList.item[i];
      S := Node.attributes.GetNamedItem('id').nodeValue;
      Val(S, ID, ErrorCode);
      if ErrorCode = 0 then begin
        if ID > Result then
          Result := ID;
      end;
    end;
  finally
    XmlDoc := Nil;
  end;
end;

end.

You need to pass your XML document as a string to this MaxID function. So, if the XML in your q were in a TMemo component on a form, you could use it like this:

var
  NewID : integer;
begin
  NewID := 1 + MaxID (Form1.Memo1.Lines.Text);
  lNewExpression.id := NewID;

There is a more direct way of getting the maximum value of an attribute, see e.g. How to find the max attribute from an XML document using Xpath 1.0 but that requires some familiarity with XPath queries and you would need to note what it says about getting the maximum value of a multi-character id.

Community
  • 1
  • 1
MartynA
  • 30,454
  • 4
  • 32
  • 73
  • Access violation... wrrr :( But, thank you very much – Maryna98 May 17 '17 at 19:06
  • The compiler does not report a bug. Only in the project(.exe) is the error pops up. Access Violation at address...... When I give ButtonClick - my code (you look up (uptade) my Code) – Maryna98 May 17 '17 at 19:23
  • 1
    The comiler wouldn't report a bug. An AV is a run-time error, not a compile -time one. Run your app and when the AV happens, go to View | Debug Windows | Call stack. The top line in the pop-up is where the AV occurred. Or, use F7 and F8 to single-step execution until the AV occurs. Btw, this stuff is **so** elementary that I'm slightly amazed you seem to have no clue how to identify where the error is occurring, never mind finding its cause. – MartynA May 17 '17 at 19:30
  • NodeList := XmlDoc.DocumentElement.childNodes; – Maryna98 May 17 '17 at 19:52
  • Then either XMLDoc or XMLDoc.DocumentElement or XmlDoc.DocumentElement.childNodes is Nil. Use Ctrl-F5 to determine which. My guess is that you aren't passing a value XML string to `MaxId`. – MartynA May 17 '17 at 19:56
  • XMLDoc.DocumentElement value = nil – Maryna98 May 17 '17 at 20:12
  • In that case, most likely you are not passing a valid XML string to `MaxId`. – MartynA May 17 '17 at 20:14
  • Maybe this is the cause?: `XMLIntf := GetDictionar(self.XMLDocument1); XMLIntf: IXMLTransportType;` – Maryna98 May 17 '17 at 20:26
  • I am not wasting time looking at code quoted without any context - you could easily post the value of the parameter you are passing to MaxId but chose not to for some reason. Like I said in my comment to to your q, post a new q written as an MCVE and revert this q to how it was. Until then, I've voted to close this q. – MartynA May 17 '17 at 20:30
  • I have updated my answer so that it contains a self-contained project which shows how to get the MaxId value from some XML. That is all I am doing. – MartynA May 17 '17 at 21:29