更新当我最初编写此q时,我的印象是blob字段的内容需要进行Base64解码,但似乎这是错误的.遵循Remy Lebeau的建议,blob流在解码之前包含字段名称和字段值中的可识别文本,但之后不包含.
Select * from Authors where au_lname = ‘White’ For XML Auto
Authors表是演示’pubs’数据库中的表.我添加了“Where”子句来限制结果集的大小,以便我可以显示返回的blob的十六进制转储.
根据sql Server OLH,指定’For XML Auto’时返回数据的默认类型是’binary base64-encoded format’.如果我让IDE创建这个字段,AdoQuery的单个字段的数据类型是ftBlob.
执行下面的代码会生成异常“DecodeToStream中的不均匀大小”.在调用IdDecoderMIME.DecodeToString(S)时,字符串S的长度为3514,3514 mod 4为2,而不是0,因为它显然应该是,因此是例外.我已经确认字段值中的字节数是3514,因此变量的大小和字符串的长度没有区别,即两者之间没有任何区别.
procedure TForm1.FormCreate(Sender: TObject); var SS : TStringStream; Output : String; S : String; IdDecoderMIME : TIdDecoderMIME; begin SS := TStringStream.Create(''); IdDecoderMIME := TIdDecoderMIME.Create(Nil); try AdoQuery1.Open; TBlobField(AdoQuery1.Fields[0]).SaveToStream(SS); S := SS.DataString; IdDecoderMIME.FillChar := #0; Output := IdDecoderMIME.DecodeToString(S); Memo1.Lines.Text := S; finally SS.Free; IdDecoderMIME.Free; end; end;
我正在使用此代码:
procedure TForm1.FormCreate(Sender: TObject); var SS : TStringStream; MS : TMemoryStream; Output : String; begin SS := TStringStream.Create(''); MS := TMemoryStream.Create; try AdoQuery1.Open; TBlobField(AdoQuery1.Fields[0]).SaveToStream(SS); SS.WriteString(#13#10); Output := SS.DataString; SS.Position := 0; MS.CopyFrom(SS,SS.Size); MS.SaveToFile(ExtractFilePath(Application.ExeName) + 'Blob.txt'); finally SS.Free; MS.Free; end; end;
Blob.Txt文件的十六进制转储如下所示
00000000 44 05 61 00 75 00 5F 00 69 00 64 00 44 08 61 00 D.a.u._.i.d.D.a. 00000010 75 00 5F 00 6C 00 6E 00 61 00 6D 00 65 00 44 08 u._.l.n.a.m.e.D. 00000020 61 00 75 00 5F 00 66 00 6E 00 61 00 6D 00 65 00 a.u._.f.n.a.m.e. 00000030 44 05 70 00 68 00 6F 00 6E 00 65 00 44 07 61 00 D.p.h.o.n.e.D.a. 00000040 64 00 64 00 72 00 65 00 73 00 73 00 44 04 63 00 d.d.r.e.s.s.D.c. 00000050 69 00 74 00 79 00 44 05 73 00 74 00 61 00 74 00 i.t.y.D.s.t.a.t. 00000060 65 00 44 03 7A 00 69 00 70 00 44 08 63 00 6F 00 e.D.z.i.p.D.c.o. 00000070 6E 00 74 00 72 00 61 00 63 00 74 00 44 07 61 00 n.t.r.a.c.t.D.a. 00000080 75 00 74 00 68 00 6F 00 72 00 73 00 01 0A 02 01 u.t.h.o.r.s..... 00000090 10 E4 04 00 00 0B 00 31 37 32 2D 33 32 2D 31 31 .......172-32-11 000000A0 37 36 02 02 10 E4 04 00 00 05 00 57 68 69 74 65 76.........White 000000B0 02 03 10 E4 04 00 00 07 00 4A 6F 68 6E 73 6F 6E .........Johnson 000000C0 02 04 0D E4 04 00 00 0C 00 34 30 38 20 34 39 36 .........408 496 000000D0 2D 37 32 32 33 02 05 10 E4 04 00 00 0F 00 31 30 -7223.........10 000000E0 39 33 32 20 42 69 67 67 65 20 52 64 2E 02 06 10 932 Bigge Rd.... 000000F0 E4 04 00 00 0A 00 4D 65 6E 6C 6F 20 50 61 72 6B ......Menlo Park 00000100 02 07 0D E4 04 00 00 02 00 43 41 02 08 0D E4 04 .........CA.....
正如您所看到的,其中一些是清晰的(字段名称和内容),其中一些不是.有没有人认识到这种格式,并且知道如何将其清理成我在SS Management Studio中执行相同查询所获得的纯文本,即如何从结果集中成功提取XML?
顺便说一句,我使用MS OLE DB Provider for sql Server和sql Server Native Client 11提供程序,并使用Delphi Seattle代替D7,得到相同的结果(包括Blob.Txt文件的内容).
鉴于代码访问外部数据库,此代码是我可以访问MCVE的最接近的代码.
更新#2如果我将SQL查询更改为,解码问题就会消失
select Convert(Text,(select * from authors where au_lname = 'White' for xml AUTO ))
它给出了结果(在SS中)
<authors au_id="172-32-1176" au_lname="White" au_fname="Johnson" phone="408 496-7223" address="10932 Bigge Rd." city="Menlo Park" state="CA" zip="94025" contract="1"/>
但我仍然有兴趣知道如何在不需要Convert()的情况下使其工作.我注意到如果我从sql中删除Where子句,返回的内容不是格式良好的XML – 它包含一系列节点,每个数据行一个节点,但没有封闭的根节点.
顺便说一下,我意识到我可以通过不使用“For XML Auto”来避免这个问题,我只是对如何正确地做到这一点感兴趣.此外,一旦我设法提取XML,我就不需要任何帮助来解析XML.