请原谅我缺乏适当的术语,因为我确信这是一个术语。我正在使用原始字符串编写XML文本(不使用任何类型的XML构建器/解析器,以便于使用)。但是,我面临的问题是,我提供的数据中的某些字符会使标准化失效。例如,&
符号。当字符串包含此字符串时,结束解析器将被抛弃。如何正确适应这一点并将字符串转换为XML标准?
我正在将简单字符串写入字符串列表并读取其Text
属性,如下所示。请注意子例程A(const S: String);
,它是将行添加到XML文件并添加必要缩进的缩短方法。请参阅子例程Standardize
,这是我需要填写的内容。
uses Windows, Classes, SysUtils, DB, ADODB, ActiveX;
function TSomething.FetchXML(const SQL: String): String;
var
L: TStringList;
Q: TADOQuery;
X, Y: Integer;
function Standardize(const S: String): String;
begin
Result:= S; //<<<--- Need to convert string to XML standards
end;
procedure A(const Text: String; const Indent: Integer = 0);
var
I: Integer;
S: String;
begin
if Indent > 0 then
for I := 0 to Indent do
S:= S + ' ';
L.Append(S + Text);
end;
begin
Result:= '';
L:= TStringList.Create;
try
Q:= TADOQuery.Create(nil);
try
Q.ConnectionString:= FCredentials.ConnectionString;
Q.SQL.Text:= SQL;
Q.Open;
A('<?xml version="1.0" encoding="UTF-8"?>');
A('<dataset Source="ECatAPI">');
A('<table>');
A('<fields>', 1);
for X := 0 to Q.FieldCount - 1 do begin
A('<field Name="'+Q.Fields[X].FieldName+'" '+
'Type="'+IntToStr(Integer(Q.Fields[X].DataType))+'" '+
'Width="'+IntToStr(Q.Fields[X].DisplayWidth)+'" />', 2);
end;
A('</fields>', 1);
A('<rows>', 1);
if not Q.IsEmpty then begin
Q.First;
while not Q.Eof do begin
A('<row>', 2);
for Y:= 0 to Q.FieldCount - 1 do begin
A('<value Field="'+Q.Fields[Y].FieldName+'">'+
Standardize(Q.Fields[Y].AsString)+'</value>', 3);
end;
A('</row>', 2);
Q.Next;
end;
end;
A('</rows>', 1);
A('</table>');
A('</dataset>');
Result:= L.Text;
Q.Close;
finally
Q.Free;
end;
finally
L.Free;
end;
end;
注意
以上是伪代码,复制和修改,无关的事情已被更改/排除......
更多信息
此应用程序是一个独立的Web服务器,提供对数据的只读访问。我只需要编写XML数据,我不需要阅读它。即使我这样做,我也有一个覆盖该部分的XML解析器库。我试图尽可能保持这种轻量级,而不用不必要的物体填充内存。
答案 0 :(得分:4)
不要手动生成XML。
编写用于转义复杂数据的正确代码(例如XML,HTML或其他XML格式的SGML,转发CDATA)是不值得的。
你逃脱的是just a start。等到有人在您的数据中放入不兼容的内容。
许多数据库支持从查询中创建格式良好的XML(请参阅其他答案),这是您应该研究的方向。
答案 1 :(得分:3)
另一个提示:也许您的数据库支持以XML格式生成结果。
答案 2 :(得分:1)
杰里&#39;解决方案很好。
值得注意的是,现有的VCL程序可以做到这一点。
单元IdStrings具有StrXHtmlEncode()。这与Jerry的解决方案完全相同。
单元HttpApp有HTMLEncode()。这个函数比Jerry的解决方案更有效 - 但是要注意 - 这个过程实际上已经打破了unicode字符串。它在pre unicode编译器中正常工作,但是没有针对unicode正确升级,并且错误从未得到修复。
添加了替换的HttpApp.HTMLEncode()的unicode安全版本如下。它比StringReplace()风格更详细,但在运行时性能方面效率更高。 (它是XML和XHTHML的预定义实体,但不适用于HTML 4)。
function XHTMLEncode( const sRawValue: string): string;
var
Sp, Rp: PChar;
begin
SetLength( result, Length( sRawValue) * 10);
Sp := PChar( sRawValue);
Rp := PChar( result);
while Sp^ <> #0 do
begin
case Sp^ of
'&': begin
FormatBuf( Rp^, 10, '&', 10, []);
Inc(Rp,4);
end;
'<',
'>': begin
if Sp^ = '<' then
FormatBuf(Rp^, 8, '<', 8, [])
else
FormatBuf(Rp^, 8, '>', 8, []);
Inc(Rp,3);
end;
'"': begin
FormatBuf(Rp^, 12, '"', 12, []);
Inc(Rp,5);
end;
'''': begin
FormatBuf(Rp^, 12, ''', 12, []);
Inc(Rp,5);
end;
else
Rp^ := Sp^
end;
Inc(Rp);
Inc(Sp);
end;
SetLength( result, Rp - PChar( result))
end;
答案 3 :(得分:0)
由于上述问题的评论,我已经实现了一个用适当的名称替换预定义实体的函数。这是新的子程序:
function EncodeXmlStr(const S: String): String;
begin
Result:= StringReplace(S, '&', '&', [rfReplaceAll]);
Result:= StringReplace(Result, '''', ''', [rfReplaceAll]);
Result:= StringReplace(Result, '"', '"', [rfReplaceAll]);
Result:= StringReplace(Result, '<', '<', [rfReplaceAll]);
Result:= StringReplace(Result, '>', '>', [rfReplaceAll]);
end;