Convert non-delimited text to name / value pairs in Delphi
I have a text file that comes into my application as many lines of the following form:
<row amount = "192.00" store = "10" transaction_date = "2009-10-22T12: 08: 49.640" comp_name = "blah" comp_ref = "C65551253E7A4589A54D7CCD468D8AFA" name = "Accrington" />
and I would like to include that string in a series of name / value pairs in a given TStringList (there can be dozens of these <row> s in the file , so eventually I will want to iterate through the file, breaking each line into name / value pairs in turn).
The problem is that the data is clearly unlimited (technically, I suppose this space is limited). Now, if it weren't for the fact that some of the values contain leading or trailing spaces, I could probably make some reasonable assumptions and code to split the string based on spaces. But since the values themselves may or may not contain spaces, I see no obvious way to do this. Delphi 'TStringList.CommaText doesn't help and I tried playing with Delimiter but every time I get missing spaces inside the values.
Does anyone have Delphi's clever method for turning the sample above into something similar to this ?;
amount = "192.00" store = "10" transaction_date = "2009-10-22T12: 08: 49.640" comp_name = "blah" comp_ref = "C65551253E7A4589A54D7CCD468D8AFA" name = "Accrington"
Unfortunately, as is usually the case with this kind of thing, I have no control over the format of the data to begin with - I can't go back and "make" it a comma in the source, for example. Although I think I could write some code to turn it into a comma separator - I'd rather find a good way to work with what I have.
It will be in Delphi 2007 if it matters.
a source to share
procedure RowToStrings(const row: string; list: TStrings);
var
i : integer;
iDelim : integer;
inQuotes: boolean;
begin
iDelim := 0;
inQuotes := false;
for i := 1 to Length(row) do begin
if (row[i] = ' ') and (not inQuotes) then begin
list.Add(Copy(row, iDelim+1, i-iDelim-1));
iDelim := i;
end
else if row[i] = '"' then
inQuotes := not inQuotes;
end;
list.Add(Copy(row, iDelim+1, Length(row)-iDelim));
end;
procedure TForm37.Test;
var
row: string;
begin
row := 'amount="192.00" store="10" transaction_date="2009-10-22T12:08:49.640" ' +
'comp_name="blah " ' +
'comp_ref="C65551253E7A4589A54D7CCD468D8AFA" ' +
'name="Accrington "';
RowToStrings(row, ListBox1.Items);
end;
a source to share
You say it's not "obviously limited", but it's very obviously limited to me because it's very obvious XML. So use an XML parser. You can start with Delphi TXmlDocument
. You can pass each line of the line to the parser separately, but my suspicion is that all of those lines are enclosed in some other angle bracket tag. Feed the whole file to a parser and it can help you get a list of objects representing strings, and then you can query the values of their attributes by name.
If you try to parse XML without paying attention to the nuances of XML parsing, sooner or later you will burn yourself out.
a source to share