Przeglądanie struktur XML

Flash Player 9 i nowsze wersje, Adobe AIR 1.0 i nowsze wersje

Jedną z największych zalet języka XML jest możliwość odzwierciedlenia złożonych, zagnieżdżonych struktur danych w postaci liniowego ciągu znaków tekstowych. Podczas ładowania danych do obiektu XML środowisko ActionScript analizuje te dane i umieszcza ich hierarchiczną strukturę w pamięci (lub zgłasza błąd, jeśli dane XML nie są poprawnie sformatowane).

Operatory i metody obiektów XML oraz XMLList ułatwiają programowe przeglądanie struktury danych XML.

Kropka (.) oraz akcesor węzła podrzędnego (..) umożliwiają dostęp do właściwości podrzędnych obiektu XML. Rozważmy następujący obiekt XML:

var myXML:XML =  
    <order> 
        <book ISBN="0942407296"> 
            <title>Baking Extravagant Pastries with Kumquats</title> 
            <author> 
                <lastName>Contino</lastName> 
                <firstName>Chuck</firstName> 
            </author> 
            <pageCount>238</pageCount> 
        </book> 
        <book ISBN="0865436401"> 
            <title>Emu Care and Breeding</title> 
            <editor> 
                <lastName>Case</lastName> 
                <firstName>Justin</firstName> 
            </editor> 
            <pageCount>115</pageCount> 
        </book> 
    </order>

myXML.book to obiekt XMLList zawierający właściwości podrzędne obiektu myXML o nazwie book. Są to dwa obiekty XML, odpowiadające dwóm właściwościom book obiektu myXML.

myXML..lastName to obiekt XMLList zawierający wszystkie elementy podrzędne o nazwie lastName. Są to dwa obiekty XML odpowiadające dwóm właściwościom lastName obiektu myXML.

myXML.book.editor.lastName to obiekt XMLList zawierający wszystkie elementy podrzędne o nazwie lastName elementów podrzędnych o nazwie editor elementów podrzędnych o nazwie book obiektu myXML : w tym przypadku obiekt XMLList zawierający tylko jeden obiekt XML (właściwość lastName o wartości "Case").

Dostęp do węzłów nadrzędnych i podrzędnych

Metoda parent() zwraca obiekt nadrzędny danego obiektu XML.

Do konkretnych obiektów podrzędnych można odwoływać się poprzez ich numery kolejne na liście obiektów podrzędnych. Rozważmy na przykład obiekt XML myXML, który ma dwie właściwości podrzędne o nazwie book. Każda właściwość podrzędna o nazwie book ma przypisany numer (indeks):

myXML.book[0] 
myXML.book[1]

Aby odwołać się do obiektu podrzędnego o dwa poziomy niżej (do „wnuka”), należy określić indeksy zarówno obiektu podrzędnego (pierwszy poziom), jak i jego obiektu podrzędnego (drugi poziom).

myXML.book[0].title[0]

Jeśli jednak istnieje tylko jeden obiekt podrzędny obiektu x.book[0] o nazwie title, można pominąć indeks:

myXML.book[0].title

Podobnie, jeśli istnieje tylko jeden element podrzędny book obiektu x, i jeśli ten obiekt podrzędny ma tylko jeden obiekt title, można pominąć oba indeksy:

myXML.book.title

Metoda child() umożliwia przechodzenie do elementów podrzędnych o nazwach określonych jako wartość zmiennej lub wyrażenia, co ilustruje następujący przykład:

var myXML:XML =  
        <order> 
            <book> 
                <title>Dictionary</title> 
            </book> 
        </order>; 
 
var childName:String = "book"; 
 
trace(myXML.child(childName).title) // output: Dictionary

Dostęp do atrybutów

Symbol @ (identyfikator atrybutu) umożliwia dostęp do atrybutów w obiekcie XML lub XMLList, co ilustruje następujący przykład:

var employee:XML =  
    <employee id="6401" code="233"> 
        <lastName>Wu</lastName> 
        <firstName>Erin</firstName> 
    </employee>; 
trace(employee.@id); // 6401

Symbol wieloznaczny * oraz symbol @ umożliwiają dostęp do wszystkich atrybutów obiektu XML lub XMLList, co zilustrowano poniżej:

var employee:XML =  
    <employee id="6401" code="233"> 
        <lastName>Wu</lastName> 
        <firstName>Erin</firstName> 
    </employee>; 
trace(employee.@*.toXMLString());  
// 6401 
// 233

Z kolei metody attribute() oraz attributes() pozwalają na dostęp do konkretnego atrybutu lub wszystkich atrybutów obiektu XML lub XMLList, tak jak widzimy poniżej:

var employee:XML =  
    <employee id="6401" code="233"> 
        <lastName>Wu</lastName> 
        <firstName>Erin</firstName> 
    </employee>; 
trace(employee.attribute("id")); // 6401 
trace(employee.attribute("*").toXMLString());  
// 6401 
// 233 
trace(employee.attributes().toXMLString());  
// 6401 
// 233

Należy zwrócić uwagę, że dostęp do atrybutów jest możliwy przy użyciu także następującej składni:

employee.attribute("id") 
employee["@id"] 
employee.@["id"]

Wszystkie zapisy są równoważne employee.@id. Jednak składnia employee.@id jest preferowana.

Filtrowanie według wartości atrybutów lub elementów

Operatory nawiasów — ( oraz ) — umożliwiają filtrowanie elementów na podstawie nazwy lub wartości atrybutu: Rozważmy następujący obiekt XML:

var x:XML =  
    <employeeList> 
        <employee id="347"> 
            <lastName>Zmed</lastName> 
            <firstName>Sue</firstName> 
            <position>Data analyst</position> 
        </employee> 
        <employee id="348"> 
            <lastName>McGee</lastName> 
            <firstName>Chuck</firstName> 
            <position>Jr. data analyst</position> 
        </employee> 
    </employeeList>

Wszystkie poniższe wyrażenia są poprawne:

  • x.employee.(lastName == "McGee") — to jest drugi węzeł employee.

  • x.employee.(lastName == "McGee").firstName — to jest właściwość firstName drugiego węzła employee.

  • x.employee.(lastName == "McGee").@id — to jest wartość atrybutu id drugiego węzła employee.

  • x.employee.(@id == 347) — pierwszy węzeł employee.

  • x.employee.(@id == 347).lastName — to jest właściwość lastName pierwszego węzła employee.

  • x.employee.(@id > 300) — to jest obiekt XMLList z obiema właściwościami employee.

  • x.employee.(position.toString().search("analyst") > -1) — to jest obiekt XMLList z obiema właściwościami position.

Próba filtrowania na podstawie nieistniejących atrybutów lub elementów spowoduje wygenerowanie wyjątku. Na przykład ostatni wiersz poniższego kodu wywoła błąd, ponieważ nie istnieje atrybut id w drugim elemencie p:

var doc:XML =  
            <body> 
                <p id='123'>Hello, <b>Bob</b>.</p> 
                <p>Hello.</p> 
            </body>; 
trace(doc.p.(@id == '123'));

Podobnie ostatni wiersz poniższego kodu wywoła błąd, ponieważ nie istnieje właściwość b drugiego elementu p:

var doc:XML =  
            <body> 
                <p id='123'>Hello, <b>Bob</b>.</p> 
                <p>Hello.</p> 
            </body>; 
trace(doc.p.(b == 'Bob'));

Aby uniknąć tych błędów, można zidentyfikować właściwości ze zgodnymi atrybutami elementami, korzystając z metod attribute() i elements(), tak jak w poniższym kodzie:

var doc:XML =  
            <body> 
                <p id='123'>Hello, <b>Bob</b>.</p> 
                <p>Hello.</p> 
            </body>; 
trace(doc.p.(attribute('id') == '123')); 
trace(doc.p.(elements('b') == 'Bob'));

Możliwe jest także użycie metody hasOwnProperty():

var doc:XML =  
            <body> 
                <p id='123'>Hello, <b>Bob</b>.</p> 
                <p>Hello.</p> 
            </body>; 
trace(doc.p.(hasOwnProperty('@id') && @id == '123')); 
trace(doc.p.(hasOwnProperty('b') && b == 'Bob'));

Korzystanie z instrukcji for..in oraz for each..in

Język ActionScript 3.0 zawiera instrukcję for..in oraz instrukcję for each..in, które umożliwiają iteracyjne przeglądanie obiektów XMLList. Rozważmy na przykład następujący obiekt XML, myXML, oraz obiekt XMLList myXML.item. Obiekt XMLList myXML.item zawiera dwa węzły item obiektu XML.

var myXML:XML =  
    <order> 
        <item id='1' quantity='2'> 
            <menuName>burger</menuName> 
            <price>3.95</price> 
        </item> 
        <item id='2' quantity='2'> 
            <menuName>fries</menuName> 
            <price>1.45</price> 
        </item> 
    </order>;

Pętla for..in umożliwia iteracyjne przeglądanie zbioru nazw właściwości w obiekcie XMLList:

var total:Number = 0; 
for (var pname:String in myXML.item) 
{ 
    total += myXML.item.@quantity[pname] * myXML.item.price[pname]; 
}

Pętla for each..in umożliwia iteracyjne przeglądanie właściwości w obiekcie XMLList:

var total2:Number = 0; 
for each (var prop:XML in myXML.item) 
{ 
    total2 += prop.@quantity * prop.price; 
}