Yerel JSON işlevini kullanma

ActionScript 3.0, ActionScript nesnelerini JavaScript Nesne Gösterimi (JSON) biçimi kullanarak kodlamak ve bunların kodunu çözmek için yerel bir API sağlar. JSON sınıfı ve destekleyici öğe işlevleri, çok az farkla ECMA-262 5. sürüm belirtimini izler.

JSON API'sine genel bakış

ActionScript JSON API'si, JSON sınıfı ve birkaç yerel sınıftaki toJSON() üye işlevlerinden oluşur. Herhangi bir sınıfa yönelik özel JSON kodlaması gerektiren uygulamalar için ActionScript çerçevesi, varsayılan kodlamayı geçersiz kılmaya yönelik yollar sağlar.

JSON sınıfı, toJSON() üyesi sağlamayan herhangi bir ActionScript sınıfı için içe aktarmayı ve dışa aktarmayı dahili olarak işler. Bu durumlar için JSON, karşılaştığı her nesnenin ortak özelliklerine çapraz geçiş uygular. Bir nesne başka nesneler içeriyorsa JSON, yuvalanmış nesnelerde yinelenir ve aynı çapraz geçişi gerçekleştirir. Herhangi bir nesne toJSON() yöntemi sunuyorsa JSON, iç algoritmaları yerine bu özel yöntemi kullanır.

JSON arabirimi stringify() kodlama yöntemi ve parse() kod çözme yönteminden oluşur. Bu yöntemlerin her biri, JSON kodlama veya kod çözme iş akışına kendi mantığınızı eklemenize olanak tanıyan bir parametre sağlar. Bu parametre, stringify() için replacer , parse() için ise reviver olarak adlandırılır. Bu parametreler, aşağıdaki imzayı kullanarak iki bağımsız değişkenli bir işlev tanımı alır:

function(k, v):*

toJSON() yöntemleri

toJSON() yönteminin imzası şudur:

public function toJSON(k:String):*

Varsa, JSON.stringify() öğesi, nesne çapraz geçişi sırasında karşılaştığı her bir ortak özellik için toJSON() öğesini çağırır. Özellik anahtar-değer çiftinden oluşur. stringify( , toJSON() öğesini çağırdığında o anda incelemekte olduğu özelliğin anahtarını ( k ) iletir. Tipik bir toJSON() uygulaması, her bir özellik adını inceler ve istenen kodlama değerini getirir.

toJSON() yöntemi, yalnızca bir String öğesini değil herhangi bir türün değerini (* olarak belirtilen) döndürebilir. Bu değişken döndürme türü toJSON() öğesinin bir nesneyi, uygunsa, döndürmesine olanak tanır. Örneğin, özel sınıfınızın bir özelliği üçüncü taraf bir kütüphaneden nesne içeriyorsa, bu nesneyi toJSON() özelliğinizle karşılaştığında döndürebilirsiniz. Sonrasında JSON üçüncü taraf nesnesinde yinelenir. Kodlama işlem akışı aşağıdaki şekilde davranır:

  • toJSON() öğesi, dizeyi değerlendirmeyen bir nesne döndürürse stringify() öğesi bu nesnede yinelenir.

  • toJSON() bir dize döndürürse, stringify() bu değeri başka bir dizede sarar, sarılmış dizeyi döndürür ve ardından bir sonraki değere geçer.

Birçok durumda, bir nesne döndürmek uygulamanız tarafından oluşturulan JSON dizesini döndürmeye tercih edilir. Bir nesne döndürmek, yerleşik JSON kodlaması algoritmasından faydalanır ve ayrıca JSON öğesinin yuvalanmış nesnelerde yinelenmesine izin verir.

toJSON() yöntemi, Object sınıfı veya diğer birçok yerel sınıfta tanımlanmaz. Yokluğu, JSON'a nesnenin ortak özellikleri üzerinde standart çapraz geçişini gerçekleştirmesini belirtir. İsterseniz, nesnenizin özel özelliklerini göstermek için toJSON() öğesini de kullanabilirsiniz.

Birkaç yerel sınıf, ActionScript kütüphanelerinin tüm kullanma durumları için etkin bir şekilde çözemediği güçlüklere neden olur. ActionScript, bu sınıflar için, istemcilerin ihtiyaçlarına uyması için yeniden uygulayabileceği küçük bir uygulama sağlar. Önemsiz toJSON() üyeleri sağlayan sınıflar şunlardır:

  • ByteArray

  • Date

  • Dictionary

  • XML

ByteArray sınıfını, toJSON() yönteminin üzerine yazmak için alt sınıflandırabilirsiniz veya sınıfın prototipini yeniden tanımlayabilirsiniz. Son olarak belirtilen Date ve XML sınıfları, toJSON() öğesini yeniden tanımlamak için sınıf prototipini kullanmanızı gerektirir. Dictionary sınıfı dinamik olarak belirtilir ve bu size toJSON() öğesinin üzerine yazmanız için fazladan özgürlük verir.

Özel JSON davranışını tanımlama

Yerel sınıflar için kendi JSON kodlamanızı ve kod çözme işleminizi uygulamak için birkaç seçenek arasından seçim yapabilirsiniz:

  • Nihai olmayan yerel bir sınıfın özel alt sınıfında toJSON() öğesini tanımlama veya geçersiz kılma

  • Sınıf prototipinde toJSON() öğesini tanımlama veya yeniden tanımlama

  • Dinamik bir sınıfta toJSON özelliğini tanımlama

  • JSON.stringify() replacer ve JSON.parser() reviver parametrelerini kullanma

toJSON() öğesini yerleşik bir sınıf prototipinde tanımlama

ActionScript'teki yerel JSON uygulaması, ECMA-262, 5. sürümde tanımlanan ECMAScript JSON mekanizmasını yansıtır. ECMAScript, sınıfları desteklemediğinden ActionScript, JSON davranışını prototip bazlı gönderme bakımından tanımlar. Prototipler benzetilmiş devralma işleminin yanı sıra üye eklentilerine ve yeniden tanımlamalarına izin veren ActionScript 3.0 sınıfı habercileridir.

ActionScript, toJSON() öğesini herhangi bir sınıf prototipinde tanımlamanıza ve yeniden tanımlamanıza olanak tanır. Bu ayrıcalık, son olarak işaretlenmiş sınıflar için bile geçerlidir. toJSON() öğesini bir sınıf prototipinde tanımladığınızda tanımınız, uygulama alanınızda bu sınıfın tüm örnekleri için geçerli olur. Örneğin burada bir toJSON() yöntemini MovieClip prototipinde nasıl tanımlayabileceğiniz bulunmaktadır:

MovieClip.prototype.toJSON = function(k):* { 
    trace("prototype.toJSON() called."); 
    return "toJSON"; 
} 

Sonrasında uygulamanız stringify() öğesini herhangi bir MovieClip örneğinde çağırdığında stringify() öğesi, toJSON() yönteminizin çıktısını döndürür:

var mc:MovieClip = new MovieClip(); 
var js:String = JSON.stringify(mc); //"prototype toJSON() called." 
trace("js: " + js); //"js: toJSON"

Ayrıca yöntemi tanımlayan yerel sınıflarda toJSON() öğesini geçersiz kılabilirsiniz. Örneğin, aşağıdaki kod Date.toJSON() öğesini geçersiz kılar:

Date.prototype.toJSON = function (k):* { 
    return "any date format you like via toJSON: "+ 
        "this.time:"+this.time + " this.hours:"+this.hours; 
} 
var dt:Date = new Date(); 
trace(JSON.stringify(dt)); 
// "any date format you like via toJSON: this.time:1317244361947 this.hours:14" 

Sınıf düzeyinde toJSON() öğesini tanımlama veya geçersiz kılma

toJSON() öğesini yeniden tanımlamak üzere prototipleri kullanmak için uygulamalara her zaman gerek yoktur. Üst sınıf nihai olarak işaretlenmemişse toJSON() öğesini bir alt sınıfın üyesi olarak tanımlayabilirsiniz. Örneğin, ByteArray sınıfını genişletebilir ve genel bir toJSON() işlevi belirtebilirsiniz:

package { 
 
    import flash.utils.ByteArray; 
    public class MyByteArray extends ByteArray 
    { 
        public function MyByteArray() { 
        } 
         
        public function toJSON(s:String):* 
        { 
            return "MyByteArray"; 
        } 
 
    } 
} 
 
 
var ba:ByteArray = new ByteArray(); 
trace(JSON.stringify(ba)); //"ByteArray" 
var mba:MyByteArray = new MyByteArray(); //"MyByteArray" 
trace(JSON.stringify(mba)); //"MyByteArray"

Bir sınıf dinamikse bu sınıfın nesnesine toJSON özelliğini ekleyebilirsiniz ve buna aşağıda olduğu gibi bir işlev atayabilirsiniz:

var d:Dictionary = new Dictionary(); 
trace(JSON.stringify((d))); // "Dictionary" 
d.toJSON = function(){return {c : "toJSON override."};} // overrides existing function 
trace(JSON.stringify((d))); // {"c":"toJSON override."}

toJSON() öğesini herhangi bir ActionScript sınıfında geçersiz kılabilir, tanımlayabilir veya yeniden tanımlayabilirsiniz. Ancak, çoğu yerleşik ActionScript sınıfı toJSON() öğesini tanımlamaz. Object sınıfı toJSON öğesini kendi varsayılan prototipinde tanımlamaz veya onu bir sınıf üyesi olarak bildirmez. Yerel sınıfların yalnızca çok azı yöntemi bir prototip işlevi olarak tanımlar. Bu nedenle toJSON() öğesini çoğu sınıfta geleneksel anlamda geçersiz kılamazsınız.

toJSON() öğesini tanımlamayan yerel sınıflar dahili JSON uygulaması tarafından JSON öğesine serileştirilirler. Mümkünse bu yerleşik işlevi değiştirmekten kaçının. Bir toJSON() öğesi tanımlarsanız, JSON sınıfı kendi işlevselliği yerine sizin mantığınızı kullanır.

JSON.stringify() değiştirici parametresini kullanma

Prototip üstünde toJSON() öğesinin üzerine yazma, uygulamada bir sınıfın JSON dışa aktarma davranışını değiştirmek için yararlıdır. Ancak bazı durumlarda, dışa aktarma mantığınız yalnızca geçici koşullar altındaki özel durumlar için geçerli olabilir. Böyle küçük kapsam değişikliklerini düzenlemek için JSON.stringify() yönteminin replacer parametresini kullanabilirsiniz.

stringify() yöntemi, replacer parametresinden kodlanmakta olan nesneye geçirilen işlevi uygular. Bu işlevin imzası toJSON() öğesininkine benzer:

function (k,v):* 

toJSON() öğesinden farklı olarak, replacer işlevi anahtarın ( k ) yanı sıra değeri de ( v ) gerektirir. Bu farklılık, stringify() öğesi, kodlanmakta olan nesne yerine statik JSON nesnesinde arandığı için gereklidir. JSON.stringify() öğesi, replacer(k,v) öğesini çağırdığında orijinal girdi nesnesini çapraz geçiyordur. replacer işlevine iletilen örtük this parametresi, anahtarı ve değeri tutan nesne ile ilgilidir. JSON.stringify() öğesi, orijinal girdi nesnesini değiştirmediği için bu nesne kapsayıcıda çapraz geçirilerek değiştirilmemiş olarak kalır. Bu nedenle, orijinal nesnedeki anahtarı sorgulamak için this[k] kodunu kullanabilirsiniz. v parametresi, toJSON() öğesinin dönüştürdüğü değeri tutar.

toJSON() gibi, replacer işlevi de herhangi bir değer türünü döndürebilir. replacer öğesi bir dize döndürürse JSON motoru, tırnak içindeki içeriklerden kurtulur ve ardından kurtulan içerikleri tırnak içine kaydırır. Bu kaydırma işlemi, stringify() öğesinin, JSON.parse() öğesini sonraki çağırışında bir dize olarak kalan geçerli bir JSON dizesi nesnesini almasını garantiler.

Aşağıdaki kod, replacer parametresi ile örtük this parametresini, Date nesnesinin time ve hours değerlerini döndürmek için kullanır:

JSON.stringify(d, function (k,v):* { 
    return "any date format you like via replacer: "+ 
        "holder[k].time:"+this[k].time + " holder[k].hours:"+this[k].hours; 
});

JSON.parse() reviver parametresini kullanma

JSON.parse() yönteminin reviver parametresi, replacer işlevinin tersini yapar: JSON dizesini kullanılabilir bir ActionScript nesnesine dönüştürür. reviver bağımsız değişkeni, iki parametre alan ve herhangi bir tür döndüren bir işlevdir:

function (k,v):* 

Bu işlevde, k öğesi bir anahtardır ve v öğesi, k öğesinin değeridir. stringify() öğesi gibi parse() öğesi, JSON anahtar-değer çiftlerini çapraz geçer ve varsa, reviver işlevini her bir çifte uygular. Olası bir problem, JSON sınıfının, bir nesnenin ActionScript sınıfı adının çıktısını almamasıdır. Bu nedenle, ne tür bir nesnenin kullanıma geçirileceğini bilmek zorlu olabilir. Bu problem özellikle nesneler iç içe geçmiş olduğu zaman sorun olabilir. toJSON() , replacer ve reviver işlevlerinin tasarlanması sırasında, orijinal nesneleri bozulmadan tutarken dışa aktarılan ActionScript nesnelerini tanımlamak için yollar bulabilirsiniz.

Ayrıştırma örneği

Aşağıdaki örnek, JSON dizelerinden ayrıştırılan nesneleri kullanıma geçirmek için bir strateji göstermektedir. Bu örnek iki sınıfı tanımlar: JSONGenericDictExample ve JSONDictionaryExtnExample. JSONGenericDictExample sınıfı özel bir sözlük sınıfıdır. Her kayıt, bir kişinin eşsiz kimliğinin yanı sıra adını ve doğum tarihini içerir. JSONGenericDictExample yapıcısı her çağrıldığında yeni oluşturulan nesneyi, kimlik olarak statik olarak artan bir tamsayı ile dahili bir statik dizeye ekler. JSONGenericDictExample sınıfı, daha uzun olan id üyesinden sadece tamsayı kısmını ayıklayan revive() yöntemini tanımlar. revive() yöntemi bu tamsayıyı, kullanıma geçirilebilir doğru nesneyi arayıp bulması ve döndürmesi için kullanır.

JSONGenericDictExample sınıfı, ActionScript Dictionary sınıfını genişletir. Kayıtları küme yapısına sahip değildir ve herhangi bir veriyi içerebilir. Veri, sınıf tanımlı özellikler olarak atanmak yerine, JSONDictionaryExtnExample nesnesi oluşturulduktan sonra atanır. JSONDictionaryExtnExample kayıtları anahtar olarak JSONGenericDictExample nesnelerini kullanır. Bir JSONDictionaryExtnExample nesnesi kullanıma geçirildiğinde JSONGenericDictExample.revive() işlevi, doğru anahtar nesnesini almak için JSONDictionaryExtnExample ile ilişkili kimliği kullanır.

En önemlisi, JSONDictionaryExtnExample.toJSON() yönteminin, JSONDictionaryExtnExample nesnesine ek olarak bir işaretleyici dize döndürmesidir. Bu dize, JSON çıktısını JSONDictionaryExtnExample sınıfına aitmiş gibi tanımlar. Bu işaretleyici, JSON.parse() sırasında hangi nesne türünün işlendiği konusunda hiçbir şüphe bırakmaz.

package { 
    // Generic dictionary example: 
    public class JSONGenericDictExample { 
        static var revivableObjects = []; 
        static var nextId = 10000; 
        public var id; 
        public var dname:String; 
        public var birthday; 
 
        public function JSONGenericDictExample(name, birthday) { 
            revivableObjects[nextId] = this; 
            this.id       = "id_class_JSONGenericDictExample_" + nextId; 
            this.dname     = name; 
            this.birthday = birthday; 
            nextId++; 
        } 
        public function toString():String { return this.dname; } 
        public static function revive(id:String):JSONGenericDictExample { 
            var r:RegExp = /^id_class_JSONGenericDictExample_([0-9]*)$/; 
            var res = r.exec(id); 
            return JSONGenericDictExample.revivableObjects[res[1]]; 
        } 
    } 
} 
 
package { 
    import flash.utils.Dictionary; 
    import flash.utils.ByteArray; 
 
    // For this extension of dictionary, we serialize the contents of the 
    // dictionary by using toJSON 
    public final class JSONDictionaryExtnExample extends Dictionary { 
        public function toJSON(k):* { 
            var contents = {}; 
            for (var a in this) { 
                contents[a.id] = this[a]; 
            } 
     
            // We also wrap the contents in an object so that we can 
            // identify it by looking for the marking property "class E" 
            // while in the midst of JSON.parse. 
            return {"class JSONDictionaryExtnExample": contents}; 
        } 
 
        // This is just here for debugging and for illustration 
        public function toString():String { 
            var retval = "[JSONDictionaryExtnExample <"; 
            var printed_any = false; 
            for (var k in this) { 
                retval += k.toString() + "=" + 
                "[e="+this[k].earnings + 
                ",v="+this[k].violations + "], " 
                printed_any = true; 
            } 
            if (printed_any) 
                retval = retval.substring(0, retval.length-2); 
            retval += ">]" 
            return retval; 
        } 
    } 
} 

Aşağıdaki çalışma zamanı komut dosyası JSONDictionaryExtnExample nesnesinde JSON.parse() öğesini çağırdığında, reviver işlevi JSONDictionaryExtnExample öğesindeki her nesnede JSONGenericDictExample.revive() öğesini çağırır. Bu çağrı nesne anahtarını temsil eden kimliği ayıklar. JSONGenericDictExample.revive() işlevi saklanan JSONDictionaryExtnExample nesnesini özel statik bir diziden almak ve döndürmek için bu kimliği kullanır.

import flash.display.MovieClip; 
import flash.text.TextField; 
 
var a_bob1:JSONGenericDictExample = new JSONGenericDictExample("Bob", new Date(Date.parse("01/02/1934"))); 
var a_bob2:JSONGenericDictExample = new JSONGenericDictExample("Bob", new Date(Date.parse("05/06/1978"))); 
var a_jen:JSONGenericDictExample = new JSONGenericDictExample("Jen", new Date(Date.parse("09/09/1999"))); 
 
var e = new JSONDictionaryExtnExample(); 
e[a_bob1] = {earnings: 40, violations: 2}; 
e[a_bob2] = {earnings: 10, violations: 1}; 
e[a_jen]  = {earnings: 25, violations: 3}; 
 
trace("JSON.stringify(e): " + JSON.stringify(e)); // {"class JSONDictionaryExtnExample": 
                        //{"id_class_JSONGenericDictExample_10001": 
                        //{"earnings":10,"violations":1}, 
                        //"id_class_JSONGenericDictExample_10002": 
                        //{"earnings":25,"violations":3}, 
                        //"id_class_JSONGenericDictExample_10000": 
                        // {"earnings":40,"violations":2}}} 
 
var e_result = JSON.stringify(e); 
 
var e1 = new JSONDictionaryExtnExample(); 
var e2 = new JSONDictionaryExtnExample(); 
 
// It's somewhat easy to convert the string from JSON.stringify(e) back 
// into a dictionary (turn it into an object via JSON.parse, then loop 
// over that object's properties to construct a fresh dictionary). 
// 
// The harder exercise is to handle situations where the dictionaries 
// themselves are nested in the object passed to JSON.stringify and 
// thus does not occur at the topmost level of the resulting string. 
// 
// (For example: consider roundtripping something like 
//   var tricky_array = [e1, [[4, e2, 6]], {table:e3}] 
// where e1, e2, e3 are all dictionaries.  Furthermore, consider 
// dictionaries that contain references to dictionaries.) 
// 
// This parsing (or at least some instances of it) can be done via 
// JSON.parse, but it's not necessarily trivial.  Careful consideration 
// of how toJSON, replacer, and reviver can work together is 
// necessary. 
 
var e_roundtrip = 
    JSON.parse(e_result, 
               // This is a reviver that is focused on rebuilding JSONDictionaryExtnExample objects. 
               function (k, v) { 
                    if ("class JSONDictionaryExtnExample" in v) { // special marker tag; 
                        //see JSONDictionaryExtnExample.toJSON(). 
                       var e = new JSONDictionaryExtnExample(); 
                       var contents = v["class JSONDictionaryExtnExample"]; 
                       for (var i in contents) { 
                          // Reviving JSONGenericDictExample objects from string 
                          // identifiers is also special; 
                          // see JSONGenericDictExample constructor and 
                          // JSONGenericDictExample's revive() method. 
                           e[JSONGenericDictExample.revive(i)] = contents[i]; 
                       } 
                       return e; 
                   } else { 
                       return v; 
                   } 
               }); 
 
trace("// == Here is an extended Dictionary that has been round-tripped  =="); 
trace("// == Note that we have revived Jen/Jan during the roundtrip.    =="); 
trace("e:           " + e); //[JSONDictionaryExtnExample <Bob=[e=40,v=2], Bob=[e=10,v=1], 
                           //Jen=[e=25,v=3]>] 
trace("e_roundtrip: " + e_roundtrip); //[JSONDictionaryExtnExample <Bob=[e=40,v=2], 
                                     //Bob=[e=10,v=1], Jen=[e=25,v=3]>] 
trace("Is e_roundtrip a JSONDictionaryExtnExample? " + (e_roundtrip is JSONDictionaryExtnExample)); //true 
trace("Name change: Jen is now Jan"); 
a_jen.dname = "Jan" 
 
trace("e:           " + e); //[JSONDictionaryExtnExample <Bob=[e=40,v=2], Bob=[e=10,v=1], 
                           //Jan=[e=25,v=3]>] 
trace("e_roundtrip: " + e_roundtrip); //[JSONDictionaryExtnExample <Bob=[e=40,v=2], 
                                     //Bob=[e=10,v=1], Jan=[e=25,v=3]>]