בחזרה לעמוד הבית

שימוש ב-XMLnitro    - מאת גדי סרבניק

 

ידע מוקדם :  הכרת xml , הכרת אובייקט xml בפלאש .

 

קבצים להורדה : xmlnitro.as , קבצי דוגמא

 

xmlnitro נכתב על ידי ברנדן הול במטרה לפתור בעיה קשה בתרגום של פלאש ל-xml . בפליירים הראשונים של גרסת פלאש 5 (5,0,30,0) , שלרובנו המכריע יש , יש בעיה בטעינת קבצי xml . הבעיה היא שכל רווח (space) מחוץ לתגיות נחשב כ-node חדש , ולכן נוכל להתקל במצבים שבהם יש לנו מסמך xml שבתוכו 4 childnodes ונגן הפלאש יזהה 8 או 9 .

בואו ונסתכל לדוגמא על המסמך הבא :

<members>

            <member>

                        <name>gadi</name>

                        <hobby>sky diving</hobby>

            </member>

            <member>

                        <name>shalom</name>

                        <hobby>basketball</hobby>

            </member>

</members>

המסמך הוא קובץ xml בנוי היטב . ניתן לראות את הסדר ההרככי . ל-child הראשון (members) יש שני childnodes (member) , שלכל אחד מהם יש שני childnodes (name,hobby) .

כלומר אם אני אתרגם את המסמך לפלאש , ואני אשאל כמה childnodes יש ל-child הראשון התשובה צריכה להיות 2 , נכון ? לא נכון .

myxml=new XML();

myxml.load("test.xml");

myxml.onload=parse;

 

function parse(){

trace(this.firstChild.childNodes.length);

}

 

//output

5

זהו קובץ דוגמא שבסופו צריכה להתבצע תצוגה בחלון ה-output של התשובה ששאלנו למעלה והתשובה תהיה 5 .

 

למה זה קורה ?

 

ובכן כמו שאמרנו קודם , הרווחים שבין ה-nodes גורמים לזה שהמחשב יחשוב שיש שם עןד childnode ריק . זה הופך להיות בעייתי כאשר לדוגמא , אנחנו רוצים להוציא את הערך של ה-childnode הראשון של המסמך . במקרה זה הערך יהיה כלום , בגלל שהוא מקבל את ה-child הראשון כ-node ריק .

 

כיצד ניתן להמנע מזה ?

 

אפשרות ראשונה היא להשתמש בנגנים מאוחרים יותר (5,0,42,0) ושם להשתמש בפונקציה החדשה שמתעלמת משטחים לבנים שנקראת xml.ignoreWhite . אפשרות זו אינה מומלצת מכיוון שלקהל היעד שלכם אין את האמצעים שיש לכן לצפיה בסרט , דבר שיגרום לשוני בין התכנון שלכם , לצפיה של המשתמש .

האפשרות השניה היא להשתמש במנגנון שנקרא xmlnitro שנכתב על ידי branden hall , מגדולי מפתחי הפלאש בעולם . על ידי השימוש בסקריפט זה ניתן להשתמש בכל נגן (פלאש 5 כמובן) בפונקציית ignorewhite בצורה הבאה :

#include "xmlnitro.as"
 
myXML = new XML();   
myXML.ignoreWhite = true;
myXML.onLoad = myLoad;
myXML.load("test.xml");
 

function parse(){

trace(this.firstChild.childNodes.length);

}

 

//output

2

 

מה מכיל הקובץ xmlnitro ?

 

ובכן , הנה הטקסט ותרגומו :

 

- בדיקת הגרסא של הפלייר אצל המשתמש

Object.version = getVersion().split(",");

Object.majorVersion = int(substring(Object.version[0],Object.version[0].length, 1));

Object.minorVersion = int(Object.version[2]);

- אם הגרסא הראשית היא 5 , נגדיר מחדש את הפונקציה parsexml של אובייקט xml שמקבלת את הטקסט של המסמך והופכת אותו לעץ (פונקציה זו מתרחשת אוטומטית כאשר אנחנו משתמשים בפעולת load .

if (Object.majorVersion == 5){

            XML.prototype.parseXML = function(str){

- המשתנה treePtr מקבל את הערך של האובייקט . tags מוגדר כמערך ו-textNode מאותחל כ-null .

                        var treePtr = this;

                        var tags = new Array();

                        var textNode = null;

- בדיקת הגרסא המשנית של הפלייר (30 או 42). ב-30 לא קיים ignorewhite וב-42 קיים .

                        if (Object.minorVersion == 30){

- הפונקציה הבאה מחזירה מספר בקשר למצב הקוד – xml.status . (0= העיבוד התבצע בהצלחה ).

  Asnative() היא פונקציה שעל ידי שילוב של מספרים בארגומנט הראשון , מבצעת פונקציה מסויימת בארגומנט השני .

  במקרה הזה הפונקציה מקבלת את המחרוזת של ה-xml , שם של מערך , וארגומנט אופציונלי שאומר האם צריך ignoreWhite .

  אחרי שמתבצעת הפונקציה, tags יכיל מערך של אובייקטים , כאשר לכל אובייקט המאפיינים הבאים :

  Type – סוג ה-node : 1-node , 3-text , 4- הצהרת xml , 5- הצהרת doctype

  Value – שם ה-node , הערך שלו או הצהרה – תלוי ב-type .

  Attrib – אובייקט המכיל זוגות של כל השמות והערכים של ה-attributes של ה-node .

  Empty – ערך בוליאני המחזיר האם ה-node ריק .

   שימו לב – גם הפתיחה וגם הסגירה של node נמצאים במערך ...

  (שיעור על asnative() בקרוב ...)

                                    this.status = ASnative(300, 0)(str, tags);

                        }else{

                                    this.status = ASnative(300, 0)(str, tags, false);

                        }

- אם העיבוד התבצע בהצלחה מתחילה ההמרה

                        if (this.status == 0){

                                    var curr;

                                    var i=0;

                                    var max = tags.length;

-          ואז מתחילה ההמרה בשני האופציות , עם ובלי ignorewhite  :

1.       בדיקת כמות ה-nodes שמכילים טקסט (לא ריקים) , במשתנה i .

2.       הרצת לולאה על כל האובייקטים במערך tags , אם האובייקט הוא node אז בודקים

האם הוא node התחלה <item> או node סיום </node> ולפי זה משייכים אותו לאובייקט הכללי.

אם הוא לא node אז הוא הצהרת מסמך או הצהרת doctype .

 

 

                                    if (this.ignoreWhite){

                                                while(tags[i].type == 3){

                                                            ++i;

                                                }

                                                while (i<max){

                                                            curr = tags[i];

                                                            if (curr.type == 1){

                                                                        if (curr.value == "/"+treePtr.nodeName){

                                                                                    if (textNode != null){

                                                                                                if (treePtr.firstChild == null){

treePtr.appendChild(this.createTextNode(textNode));

                                                                                                }

                                                                                                textNode = null;

                                                                                    }

                                                                                    treePtr = treePtr.parentNode;

                                                                        }else{

                                                                                    treePtr.appendChild(this.createElement(curr.value));

                                                                                    treePtr = treePtr.lastChild;

                                                                                    treePtr.attributes = curr.attrs;

                                                                                    if (curr.empty){

                                                                                                treePtr = treePtr.parentNode;

                                                                                    }

                                                                                    textNode = null;

                                                                        }

                                                            }else{

                                                                        if (curr.type == 3 || curr.type == 6){

                                                                                    textNode = curr.value;

                                                                        }else{

                                                                                    if (curr.type == 4){

                                                                                                this.xmlDecl = curr.value;

                                                                                    }else{

                                                                                                this.docTypeDecl = curr.value;

                                                                                    }

                                                                        }

                                                            }

                                                            ++i;

                                                }

                                    }else{

                                                while (i<max){

                                                            curr = tags[i];

                                                            if (curr.type == 1){

                                                                        if (curr.value == "/"+treePtr.nodeName){

                                                                                    treePtr = treePtr.parentNode;

                                                                        }else{

                                                                                    treePtr.appendChild(this.createElement(curr.value));

                                                                                    treePtr = treePtr.lastChild;

                                                                                    treePtr.attributes = curr.attrs;

                                                                                    if (curr.empty){

                                                                                                treePtr = treePtr.parentNode;

                                                                                    }

                                                                        }

                                                            }else{

                                                                        if (curr.type == 3 || curr.type == 6){

                                                                                    treePtr.appendChild(this.createTextNode(curr.value));

                                                                        }else{

                                                                                    if (curr.type == 4){

                                                                                                this.xmlDecl = curr.value;

                                                                                    }else{

                                                                                                this.docTypeDecl = curr.value;

                                                                                    }

                                                                        }

                                                            }

                                                            ++i;

                                                }

                                    }

                        }

            }

}