עקב העומס הרב אנו מעדכנים רק את האתר באנגלית - עמכם הסליחה

עצי ג’אווה

רקע


עצי ג’אווה הפכו לאופנה האחרונה באתרים אינטרנט ואפליקציות Web. הם זוכים לפופולאריות רבה בזכות הקלות בה ניתן להטמיע אותם לתוך מערכת קיימת, לבצע בהם שינויים ותחזוקה. בניגוד גמור לקלות ההתקנה והשימוש, ביצוע בדיקות אוטומטיות לעצי ג’אווה דינאמיים יכול להפוך לסיוט.
היום נבחן מקרוב עץ ג’אווה ייצוגי, שהפך למאוד פופולארי בפני עצמו (dTree), ושווריאציות שונות שלו צצות תחת כל עץ רענן, ומאחורי כל אתר קטן כגדול (ואפילו באתר פה!). במסגרת הטיפול בעץ נארוז הרבה קטעי קוד בפונקציות משלהם, עובדה שתאפשר לכם להשתמש בקוד שנדגים בקלות, ולהתאים אותו לצרכיכם.
 

תכנון

האסטרטגיה לניווט בעץ היא ישירה למדי: בעוד שעצי ג’אווה רבים טוענים את כלל מבנה העץ מראש, QTP יכול לתפעל רק רמה אחת בכל שלב (אם אנחנו רוצים להישאר נאמנים לפעולות המשתמש) - ולכן, אנו נעבור ונרחיב רמה-רמה בעץ בהתאם למסלול הניווט. כל העבודה תעשה מאחורי הקלעים, ברמת אובייקטים ה-Run-Time, ובפועל המעטפת של QTP תשמש אותנו רק להצבעה על שורש העץ.
היות ואני אוהב להשתמש במחרוזות משורשרות, נבנה בדוגמה זו את מסלול הניווט כמחרוזת מהצורה Level1>Level2>Level3>…, כאשר כל רמה הינה שם הצומת בעץ. היות ויתכנו צמתים שונים בעלי אותו שם, באותה רמה, הניווט לא יוכל להתבצע באופן ליניארי (אנחנו עלולים להיכנס לתוך צומת שלא מכילה את שאר מסלול הניווט). עובדה זו תאלץ אותנו להבנות את הקוד באופן רקורסיבי, וקצת יותר מסובך מהרגיל.

מבנה עצי ג’אווה

זהו המקום להיזכר כיצד בנויים רוב עצי הג’אווה: בכל רמה, לצומת האב ישנם צמתים בנים, המתחלקים לשני סוגים: הילדים הישירים של האב, וצמתים המייצגים את הנכדים של האב, בהתאם לאחד הילדים. בפועל זה נראה כך :
צומת אב
            בן1 (צומת בן אמיתי, ללא ילדים משלו)
            בן2 (צומת בן אמיתי, עם שלושה ילדים משלו)
            בן3 (צומת בן פיקטיבי, המחזיק בתוכו את שלושת הילדים של בן2)
            בן4 (צומת בן אמיתי, עם ילד אחד משלו)
            בן5 (צומת בן פיקטיבי, המחזיק בתוכו את הילד של בן4)
 
אבל כמובן שהמצב מסובך יותר ממה שתיארנו. לכל בן, יש "צמתי-עזר", הקיימים בלי קשר למספר הילדים שלו (או אם יש לו ילדים כלל). "צמתי-עזר" אלו כוללים רווחים לאינדנטציה, אייקון להרחבה/כיווץ, וכן את הטקסט (והקישור) עצמו של הצומת. כך שהתמונה האמיתית היא : היא :
צומת אב
           
            בן2 (צומת בן אמיתי, עם שלושה ילדים משלו)
                        צמתי-עזר (רווחי אינדנטציה, אייקון להרחבה, והטקסט והקישור של בן2)
            בן3 (צומת בן פיקטיבי, המחזיק בתוכו את שלושת הילדים של בן2)
           
 
בשורה התחתונה, שתי העובדות שחשוב לזכור הן:
א.      כאשר אנחנו רוצים לבצע פעולה כלשהי בצומת (הרחבה, לחיצה להפעלת קישור וכו’), אנחנו בעצם רוצים לבצע פעולה על צמתי-העזר המצויים תחת הצומת הרלוונטי.
ב.      כאשר אנחנו מדברים על הצמתים הכפופים לאב מסוים, יש לזכור כי צמתים אלו לא מצויים תחת צומת האב (שם מצויים צמתי-העזר), אלא הם מופיעים לצידו, כצומת אח פיקטיבי. צומת האב (שם מצויים צמתי-העזר), אלא הם מופיעים לצידו, כצומת אח פיקטיבי.
אנחנו עוד נראה איך עובדות אלו באות לכדי ביטוי בקוד הניווט בעץ.

הקוד

הקוד המטפל בעץ נחלק לשלושה חלקים:
תחילה, עלינו למצוא את שורש העץ: לרוב זוהי משימה קלה – השורש הוא לרוב קישור בשם "בית" או "תיקיות" או טקסט דומה. לעומת זאת, ישנם אתרים בהם השורש הינו נטול טקסט, ומסתתר מאחורי הקלעים. הוא שם, כמובן, אבל קשר לאתר אותו באמצעות שימוש במאגר האובייקטים / : לרוב זוהי משימה קלה – השורש הוא לרוב קישור בשם "בית" או "תיקיות" או טקסט דומה. לעומת זאת, ישנם אתרים בהם השורש הינו נטול טקסט, ומסתתר מאחורי הקלעים. הוא שם, כמובן, אבל קשר לאתר אותו באמצעות שימוש במאגר האובייקטים / DP. דרך אחת להתגבר עלי הבעיה, היא להשתמש באחד מהצמתים העליונים בעץ, ולהתקדם ממנו במעלה ההיררכיה :

Function GetRoot(oQTPTopLevelNode)
    Set GetRoot = oQTPTopLevelNode.Object.ParentNode.ParentNode
   ‘Notice that we climb twice up the hierarchy,
   ’since our line is actually a helper-node
End Function
 

במידה ולעץ שלכם יש שורש, ניתן לשנות את הפונקציה כך שתעלה רק רמה אחת במעלה ההיררכיה, או שתאתר את הצומת המחזיק את כל הבנים באופן אחר (הצומת עשוי להיות צומת-אח לשורש העץ). נסו ווריאציות שונות עד שתגיעו לתוצאה המתאימה לעץ שלכם.
 
כעת מגיע קוד הניווט עצמו::
פונקציית הניווט קוראת לפונקציות העזר הבאות :
IsNeededNode – בודקת האם מצאנו את הצומת שאנו צריכים לנווט אליו
ExpandNode – מרחיבה את הצומת הרלוונטית
ClickNode – מקליקה על קישור הטקסט של הצומת הרלוונטית

’sNavigate path = "level1>level2>level3>"
‘oParentNode = first it’s the root from the GetRoot function,
               ‘and later it will be recursively sent
 
Function NavigateTree(sNavigatePath, oParentNode)
   Dim arrPath ‘Breaks down the path string
   Dim i
   Dim sNeededNode ‘Holds the current node to navigate to
   Dim bNavigationSuccessful
   Dim sNewNavigatePath ‘we’ll send this down the recursive chain
 
   arrPath = Split(sNavigatePath, ">")
   sNeededNode = arrPath(0)
 
   ‘Create a new navigation path without the current node
    sNewNavigatePath = Replace(sNavigatePath, sNeededNode, "", 1, 1)
    If Mid(sNewNavigatePath ,1,1 ) = ">" Then _
                               sNewNavigatePath = Mid(sNewNavigatePath ,2)
   bNavigationSuccessful = False
   ‘Find the needed node
   For i = 0 To oParentNode.Children.Length-1 ‘Loop through all the parent’s child-nodes
     If IsNeededNode(sNeededNode, oParentNode.Children.Item(i)) Then
       Call ExpandNode(oParentNode.Children.Item(i))
 
       ‘If we’re at the end of the navigation path, we should click
       If sNewNavigatePath = ""  Then
           bNavigationSuccessful = ClickNode(oParentNode.Children.Item(i), sNeededNode)
       Else ‘We should navigate - recursively call the function
           ‘Remember - the child nodes are held at the current node sibling, NOT under it
           ‘This is why the parent we send recursively is the current+1 child,
           ‘and not the current child
           bNavigationSuccessful = NavigateTree(sNewNavigatePath, oParentNode.Children.Item(i+1))
       End If
 
      If bNavigationSuccessful = True Then Exit For ‘Navigation Completed
   
      ‘Notice that if the navigation went worng down the recursive chain,
      ‘we’ll continue searching other nodes with the same name
     End If ‘Did we find the current node?
   Next ‘Continue looping in search of the current node
 
   NavigateTree = bNavigationSuccessful
End Function
 

 
ואחרונות חביבות – פונקציות העזר:
 
‘Here you can add any custom behaivor relevant to you tree
‘For example, some tree cut the OuterText property after a certian length
‘So we should use another property or cut the expected sNodeName in the same manner
 
Function IsNeededNode(sNodeName, oNode)
   If sNodeName = Trim(oNode.OuterText) Then
    IsNeededNode = True
   Else
    IsNeededNode = False
   End If
End Function
 
‘Here we search for the expand-icon helper node, under oNodeToExpaned
Sub ExpandNode(oNodeToExpaned)
  Const sClosedNodeSearchString = "PLUS" 
        ‘This tells us that the icon is + and not -
  Const sPictureSearchString = "GIF"
        ‘This tells us the the helper node has an icon
  ‘ Change these constansts to suite you tree
  Dim i
 
  If oNodeToExpaned.Children.Length > 1 Then ‘If our parent node has helper nodes at all
    For i = 0 to oNodeToExpaned.Children.Length - 1
                                 ‘Loop through helper nodes
      If instr(uCase(oNodeToExpaned.Children.Item(i).InnerHTML), sPictureSearchString) > 0 Then
                                      ‘It’s an icon
        If instr(uCase(oNodeToExpaned.Children.Item(i).InnerHTML), sClosedNodeSearchString) > 0 Then
                                          ‘Its’ a + icon
          oNodeToExpaned.Children.Item(i).Click ‘Click the helper node, expending the tree
           ‘You can add sync or wait functions here, in order to wait for the tree to referesh
           Exit For
        End If ‘Found open-node image
      End If ‘Found IMG node
    Next
   End If ‘The node has children
End Sub
 
‘Much like ExpandNode, but this time we search for
‘the text-link helper node
Function ClickNode(oNodeClick, sNodeName)
  Dim i
    For i = 0 to oNodeClick.Children.Length - 1 ‘Loop helper nodes
      If  sNodeName = oNodeClick.Children.Item(i).outerText Then
        oNodeClick.Children.Item(i).Click
        Exit For
      End If
    Next
   ClickNode = True ‘Just for formality
End Function
 

דוגמה לניווט

שתלתי כמה צמתי דוגמה בעץ מאגר-הידע, על מנת שתוכלו להתנסות בקוד בעצמכם. העתיקו את קטעי הקוד של שלושת החלקים ל-QTP, והוסיפו בתחילתו את הקטע הבא (יתכן שסימני ה-> התהפכו, אם אתם לא מגיעים לתוצאות הרצויות, השתמשו בסימן ההפוך):
 
sNavigatePath = "מאגר הידע" & ">" & "טכניקות לסביבות ספציפ…" & ">" & "אינטרנט" & ">" & "עצי ג’אווה" & ">" & "דוגמה" & ">" & "דוגמת בת"
Set oQTPTree = Browser("title:=.*QTP.*", "index:=0").Page("title:=.*QTP.*", "index:=0").Link("html id:=spge1")
Set oRoot = GetRoot(oQTPTree)
msgbox NavigateTree(sNavigatePath, oRoot) ‘This does the actual navigation

 
ניתן לראות כיצד פונקציית הניווט מתקנת את עצמה: היא מגיעה לצומת "דוגמה" הראשון, אולם לא מוצאת בו את צומת הבן "דוגמת בת". היא ממשיכה אוטומטית לצומת "דוגמה" השני, ומנווטת אליו. ניתן לראות זאת בבירור ע"י הורדת החלק האחרון ממסלול הניווט, וכפועל יוצא הפונקציה תנווט לצומת "דוגמה" הראשון, ותסתפק בו.
 
עצי הג’אווה בפרוייקט שלכם עשויים לדרוש שינויים והרחבות לקוד, אולם אני עדיין מקווה שהדוגמאות שנתתי יעזרו לכם להתמודד איתן בקלות.  Having said that, כמובן שינם עצי ג’אווה בעלי מבנה פנימי שונים לחלוטין, ועבורם הקוד שהדגמתי לא רלוונטי לחלוטין.

שמור את המאמר לשימוש עתידי

הדפס את המאמר הדפס את המאמר
A PDF Version Of This Post


11 תגובות to “עצי ג’אווה”

  1. general אומר :

    meridia :-( order levitra 842921 accutane asvwu viagra 753 cialis dgcjn

  2. vrijemp3 אומר :

    homeowners insurance :-)) car insurance quotes 8387 auto insurance eyp auto insurance rates 01157 long term car insurance 684

  3. ralph אומר :

    health insurance curj health insurance 8-]]] life insurance >:-[ low car insurance rates :[[

  4. eller אומר :

    buy tramadol :-[[[ aciphex lnuxz what is xanax 781 buy tramadol igupcm phentermine snz 2003 cialis levitra market sales viagra 50880 generic cialis kvaphq purchase ultram for pain rbqevl

  5. netfilt אומר :

    nj car insurance %-[[[ auto insurance njhe levitra asaw

  6. password אומר :

    online casino oqdani health insurance quotes 5962 health insurance =-[[ health insurance 26257 homeownersinsurance 474403

  7. Gnuoy אומר :

    snort taranabant :-[ ambien home page aeyquh zyrtec and pulsatile tinnitus iew prozac making me worse 43504 buy valium online 567969

  8. Light_Assassin אומר :

    relief stress valium 440 weight loss diet desert burn hoodia :-DDD by inversine on line :-]]] can i drink and use celebrex 091980

  9. SPIDERFAIRY אומר :

    using acetophenazine vmhf citalopram and pdr 319 cetirizine syrup jypbkb buy nimotuzumab at yvn

  10. go4it4eva אומר :

    618 levitra ppt 891 %-]]] hoodia west virginia 4254 radio control blackjack 55 >:-DDD buy paxil without a ska

הוסף תגובה