2011-01-17 18 views
10

मैं एक्सएमएल को ऑब्जेक्ट्स को पढ़ने और लिखने के लिए डेल्फी एक्सई या बाद में उन्नत आरटीटीआई सुविधाओं का उपयोग करने का प्रयास कर रहा हूं। अब तक मैं पूर्णांक, फ्लोट्स, तार, गणित प्रकार, सेट और कक्षाओं के साथ सफल रहा हूं लेकिन रिकॉर्ड को सही ढंग से आउटपुट या पढ़ नहीं सकता। लगता है कि रिकॉर्ड रिकॉर्ड संपत्ति के लिए एक उदाहरण (सूचक) हो रहा है।रिकॉर्ड मूल्य प्राप्त करने और सेट करने के लिए डेल्फी आरटीटीआई का उपयोग कैसे करें

//Outputs Properties To XML 
procedure TMyBase.SaveToXML(node: TJclSimpleXMLElem); 
var 
    child , subchild : TjclSimpleXMLElem ; 
    FContext : TRttiContext ; 
    FType : TRttiType ; 
    FProp : TRttiProperty ; 
    Value : TValue ; 
    MyObj : TMyBase ; 
    FField : TRttiField ; 
    FRecord : TRttiRecordType ; 
    Data  : TValue ; 
begin 
    FContext := TRttiContext.Create ; 
    FType := FContext.GetType (self.ClassType) ; 
    Child := node.Items.Add (ClassName) ; 
    for FProp in FType.GetProperties do begin 
    if FProp.IsWritable then begin 
     case FProp.PropertyType.TypeKind of 
     tkClass : begin 
      MyObj := TMyBase (FProp.GetValue (self).AsObject) ; 
      MyObj.SaveClass (Child.Items.Add (FProp.Name) , FContext) ; 
      end ; 
     tkRecord : begin 
      subchild := Child.Items.Add (FProp.Name) ; 
      FRecord := FContext.GetType(FProp.GetValue(self).TypeInfo).AsRecord ; 
      for FField in FRecord.GetFields do begin 
      >>> self is not the correct instance <<< 
      Value := FField.GetValue (self) ; 
      subchild.Items.Add (FField.Name).Value := Value.ToString ; 
      end; 
      end ; 
     else begin 
      Value := FProp.GetValue(self) ; 
      Child.Items.Add (FProp.Name).Value := Value.ToString ; 
      end; 
     end; 
     end ; 
    end ; 
    FContext.Free ; 
end; 

मुझे संदेह है कि यदि मैं मान सकता हूं कि मूल्य कैसे प्राप्त करें तो उन्हें सेट करना कोई समस्या नहीं होनी चाहिए। फिर सरणी पर, ओह लड़का!

अद्यतन: कृपया below देखें। (दृश्यता में सुधार के लिए अलग जवाब के रूप में माइग्रेट किया गया)।

+0

कौन सा डेल्फी के संस्करण यहाँ संशोधित कोड है? – GolezTrol

+0

इसका एक्सई संस्करण – Mitch

+1

क्या कोई विशेष कारण है कि आप "कक्षाओं" के अंत में "रिकॉर्ड" को सहेजना चाहते हैं? यदि नहीं, तो ओमनीएक्सएमएल की जांच करें, इसमें एक * .XML फ़ाइल से/TPersistent वंशज को सहेजने और लोड करने की क्षमता है। http://www.omnixml.com/ – ComputerSaysNo

उत्तर

10

मुझे लगता है कि आप रनटाइम प्रकार के स्वयं के रिकॉर्ड-टाइप किए गए फ़ील्ड के मूल्य को बचाने की कोशिश कर रहे हैं, हां?

आपको FProp.GetValue(Self) के साथ पहले फ़ील्ड का मान प्राप्त करना होगा। आइए मान लें कि आप नामक एक चर में TValue टाइप करें। फिर आप रिकॉर्ड वैल्यू के फ़ील्ड को अपनी इच्छानुसार सहेज सकते हैं, हालांकि आप शायद इसके लिए एक रिकर्सिव प्रक्रिया लिखना चाहेंगे, क्योंकि रिकॉर्ड के क्षेत्र स्वयं फ़ील्ड हो सकते हैं। रिकॉर्ड के लिए क्षेत्र गेटटर सेटर के साथ समरूपता के लिए रिकॉर्ड के पते (इसकी शुरुआत के लिए एक सूचक) की अपेक्षा करता है; सेटर मूल्य के बजाय पते की अपेक्षा करता है क्योंकि अन्यथा किसी अन्य वर्ग या रिकॉर्ड में "सीटू में" फ़ील्ड को संशोधित करने का कोई आसान तरीका नहीं होगा, क्योंकि रिकॉर्ड अन्यथा मूल्य के आधार पर पारित होते हैं।

आप इसे FieldValue.GetReferenceToRawData के साथ प्राप्त कर सकते हैं, जो TValue के अंदर संग्रहीत रिकॉर्ड्स की शुरुआत में पॉइंटर लौटाएगा।

उम्मीद है कि यह आपको जारी रखने के लिए पर्याप्त संकेत देता है।

+0

धन्यवाद, मैं इसे आज़मा दूंगा। टीएमबीज भविष्य के वर्गों के लिए पूर्वज होगा और उन वर्गों को पढ़ने और लिखने के लिए काम करेगा। तो आत्म बचाया जाने वाला वास्तविक रन टाइम ऑब्जेक्ट है। – Mitch

+0

धन्यवाद कि काम किया! ऊपर देखो। – Mitch

+2

क्या आप में से कोई भी पुराने स्कूल लोगों को टर्बो पास्कल के दिनों को याद करता है, जब आप "एफ: फाइल ऑफ माईक्रॉर्ड" बनाकर रिकॉर्ड जारी रखेंगे, तो असाइन करें (एफ, फ़ाइल नाम), और फिर फ़ाइल में बाइनरी रिकॉर्ड सामग्री लिखें? –

4

श्रेय: मूल रूप से ओ पी (Mitch ) द्वारा प्रश्न के अपडेट के रूप में तैनात - अलग जवाब के रूप में दृश्यता में सुधार के लिए चले।

बैरी के समाधान ने चाल की।

tkRecord : begin 
     subchild := Child.Items.Add (FProp.Name) ; 
     Value := FProp.GetValue(self) ; 
     FRecord := FContext.GetType(FProp.GetValue(self).TypeInfo).AsRecord ; 
     for FField in FRecord.GetFields do begin 
     Data := FField.GetValue (Value.GetReferenceToRawData) ; 
     subchild.Items.Add (FField.Name).Value := Data.ToString ; 
     end; 
     end ; 

उन सरणियों से निपटने की जरूरत है कि के लिए::

tkDynArray : begin 
     Value := FProp.GetValue (self) ; 
     FArray := FContext.GetType(Value.TypeInfo) as TRttiDynamicArrayType ; 
     subchild := child.Items.Add (FProp.Name) ; 
     cnt := Value.GetArrayLength ; 
     subchild.Properties.Add ('Count' , cnt) ; 
     case FArray.ElementType.TypeKind of 
     tkInteger , 
     tkFloat : begin 
      for a := 0 to cnt-1 do begin 
      Data := Value.GetArrayElement (a) ; 
      subchild.Items.Add (IntToStr(a) , Data.ToString) ; 
      end; 
      end ; 
     tkRecord : begin 
      FRecord := FArray.ElementType as TRttiRecordType ; 
      for a := 0 to cnt-1 do begin 
      Data := Value.GetArrayElement (a) ; 
      subsubchild := subchild.Items.Add (IntToStr(a)) ; 
      for FField in FRecord.GetFields do 
       SaveField (subsubchild , FContext , FField , Data.GetReferenceToRawData) ; 
      end; 
      end ; 
संबंधित मुद्दे