שימוש ב-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;
}
}
}
}
}