2016-12-05 8 views
8

में एक्सएमएल ब्लॉब फ़ील्ड को डीकोड कैसे करें मुझे डी 7 में लिखे गए ऐप में एमएस एसक्यूएल सर्वर 2014 के उदाहरण द्वारा लौटाए गए एक्सएमएल डेटा को डीकोड करने का प्रयास करने में समस्या आ रही है। (इंडी का संस्करण वह है जो इसके साथ आया, 9.00.10)।डी 7

अद्यतन जब मैं मूल रूप से इस क्ष लिखा था, मैं धारणा है कि जरूरत ब्लॉब फ़ील्ड की सामग्री Base64-डीकोड किया जा करने के लिए किया जा रहा था, लेकिन ऐसा लगता है कि उस गलत था। रेमी लेबेउ के सुझाव का पालन करने के बाद, ब्लॉब स्ट्रीम में डीकोडिंग से पहले फील्ड नामों और फ़ील्ड मानों में पहचानने योग्य टेक्स्ट होता है लेकिन बाद में नहीं।

नीचे कोड में, AdoQuery में एसक्यूएल लेखक से है बस

* का चयन करें जहां au_lname = 'व्हाइट' एक्सएमएल ऑटो

लेखक तालिका डेमो में से एक होने के लिए 'पब' डेटाबेस। मैंने परिणाम सेट के आकार को प्रतिबंधित करने के लिए "कहां" खंड जोड़ा है, इसलिए मैं लौटा हुआ ब्लॉब का हेक्स डंप दिखा सकता हूं।

एसक्यूएल सर्वर ओएलएच के अनुसार, 'एक्सएमएल ऑटो के लिए' निर्दिष्ट डेटा का डिफ़ॉल्ट प्रकार 'बाइनरी बेस 64-एन्कोडेड प्रारूप' है। AdoQuery के एकल फ़ील्ड का डेटा प्रकार ftBlob है, अगर मैंने आईडीई को इस क्षेत्र को बनाने दिया है।

नीचे दिए गए कोड को निष्पादित करने से अपवाद उत्पन्न होता है "DecodeToStream में असमान आकार"। IdDecoderMIME.DecodeToString(S) पर कॉल पर, स्ट्रिंग एस की लंबाई 3514 है, और 3514 मॉड 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..... 

तरह लग रहा है आप देख सकते हैं, इसमें से कुछ सुगम (फ़ील्ड नाम और सामग्री) है, इनमें से कुछ नहीं है। क्या कोई इस प्रारूप को पहचानता है और एसएस मैनेजमेंट स्टूडियो में एक ही क्वेरी को निष्पादित करने से प्राप्त सादे पाठ में इसे साफ करने के बारे में जानता है, यानी मैं परिणाम सेट से एक्सएमएल को सफलतापूर्वक कैसे निकालूं?

बीटीडब्ल्यू, मुझे एसक्यूएल सर्वर और एसक्यूएल सर्वर मूल क्लाइंट 11 प्रदाता के लिए एमएस ओएलई डीबी प्रदाता और डी 7 के स्थान पर डेल्फी सिएटल का उपयोग करके एक ही परिणाम (Blob.Txt फ़ाइल की सामग्री सहित) मिलता है।

यह देखते हुए कि कोड बाहरी डेटाबेस तक पहुंचता है, यह कोड एमसीवीई के पास सबसे नज़दीक है।

# अद्यतन 2 डिकोडिंग समस्या गायब हो जाती है अगर मैं Sql

select Convert(Text, 
(select * from authors where au_lname = 'White' for xml AUTO 
)) 

को

<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"/> 

का जो परिणाम देता है (SS में) क्वेरी बदल लेकिन मैं अभी भी करने के लिए इच्छुक हूँ कन्वर्ट() की आवश्यकता के बिना काम करने के लिए यह कैसे पता है। मैंने देखा है कि यदि मैं एसक्यूएल से कहां से खंड हटा देता हूं, तो जो भी लौटाया जाता है वह अच्छी तरह से गठित एक्सएमएल नहीं होता है - इसमें नोड्स की एक श्रृंखला होती है, प्रति डेटा पंक्ति में एक, लेकिन कोई संलग्न रूट नोड नहीं है।

इसके अलावा, मुझे एहसास है कि मैं "एक्सएमएल ऑटो के लिए" का उपयोग न करके इस समस्या से बच सकता हूं, मुझे बस यह सही तरीके से करने में दिलचस्पी है। इसके अलावा, मुझे एक्सएमएल को पार्स करने में मदद करने के बाद मुझे किसी भी मदद की ज़रूरत नहीं है।

+0

क्या बेस 64 में पैडिंग वर्ण शामिल हैं? इसे 4 का एक भी बहुमत बनाना चाहिए। यदि नहीं, तो आप अपने 'आकार' को एक भी एकाधिक बनाने के लिए अपने 'tStringStream' के अंत में अपने पैडिंग वर्ण लिख सकते हैं (हालांकि आपको वास्तव में' TDataSet.CreateBlobStream का उपयोग करना चाहिए() '' TBlobField.SaveToStream() 'के बजाय, लेकिन फिर आप मैन्युअल रूप से पैडिंग नहीं जोड़ सकते हैं)। वैकल्पिक रूप से, इंडी 10 में अपग्रेड करने पर विचार करें, क्योंकि इसकी 'TIdDecoderMIME' इनपुट को अस्वीकार नहीं करती है जो कि 4 से भी अधिक नहीं है। –

+0

@RemyLebeau: धन्यवाद। मुझे 'TDataSet.CreateBlobStream' का उपयोग करके एक ही परिणाम मिलता है। आपके द्वारा सुझाए गए मैन्युअल पैडिंग को आजमाने के बाद, ऐसा लगता है कि बेस 64 डिकोडिंग वास्तव में आवश्यक नहीं है जिसमें यह आंशिक रूप से सुस्पष्ट पाठ को गैरकानूनी में परिवर्तित कर दे - अद्यतन q टेक्स्ट देखें। – MartynA

उत्तर

4

TYPE Directive जोड़ें यह निर्दिष्ट करने के लिए कि आप XML वापस लौटा चाहते हैं।

select * 
from Authors 
where au_lname = 'White' 
for xml auto, type 
+0

धन्यवाद। दुर्भाग्य से क्वेरी में "टाइप करें" जोड़ना प्रभाव डालता है कि AdoQuery1 ऑब्जेक्ट को 'ओपन()' पर कॉल पर बनाए गए किसी भी फील्ड ऑब्जेक्ट नहीं मिलते हैं, इसलिए किसी भी डेटा को पुनर्प्राप्त करना संभव नहीं है। क्वेरी में 'कन्वर्ट()' का उपयोग करके मेरा काम-आसपास ठीक काम करता है, हालांकि। – MartynA

+1

@ मार्टिनए अगर आप 'SQLOLEDB.1' का उपयोग करते हैं तो यह करता है। यदि आप 'SQLNCLI11.1' का उपयोग करते हैं तो आपको कनेक्शन स्ट्रिंग में' DataTypeCompatibility = 80' सेट करना होगा। –

+0

तो यह करता है! नतीजा अभी भी अच्छी तरह से गठित एक्सएमएल नहीं है, लेकिन मैं इससे निपट सकता हूं। – MartynA

2

आप एक्सएमएल में बाइनरी ब्लॉब को बस डीकोड नहीं कर सकते हैं।

आप TADOCommand का उपयोग करें और एक XML दस्तावेज वस्तु उदा .:

const 
    adExecuteStream = 1024; 
var 
    xmlDoc, RecordsAffected: OleVariant; 
    cmd: TADOCommand; 

xmlDoc := CreateOleObject('MSXML2.DOMDocument.3.0'); // or CoDomDocument30.Create; 
xmlDoc.async := False; 

cmd := TADOCommand.Create(nil);  
// specify your connection string 
cmd.ConnectionString := 'Provider=SQLOLEDB;Data Source=(local);...'; 
cmd.CommandType := cmdText; 
cmd.CommandText := 'select top 1 * from items for xml auto'; 
cmd.Properties['Output Stream'].Value := xmlDoc; 
cmd.Properties['XML Root'].Value := 'RootNode'; 
cmd.CommandObject.Execute(RecordsAffected, EmptyParam, adExecuteStream); 

xmlDoc.save('d:\test.xml'); 
cmd.Free; 

इस रूट नोड RootNode संलग्न के साथ एक अच्छी तरह से गठित XML परिणाम के लिए इसके उत्पादन धारा प्रत्यक्ष कर सकते हैं।