XML 階層構造へのアクセス

Flash Player 9 以降、Adobe AIR 1.0 以降

XML が備えている強力な機能の 1 つは、複雑にネストされたデータを、テキストの文字による連続的なストリングによって表現できることです。 データを XML オブジェクトにロードすると ActionScript によって解析され、階層構造のデータとしてメモリにロードされます(XML データが整形式でない場合はランタイムエラーが発生します)。

XML オブジェクトと XMLList オブジェクトの演算子やメソッドを使用すれば、この XML データの構造内を簡単に移動できます。

XML オブジェクトの子プロパティにアクセスするには、ドット(.)演算子と子孫アクセッサー(..)演算子を使用します。例えば、次のような 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 は XMLList オブジェクトであり、 myXML オブジェクトの book という名前を持つ子プロパティを含んでいます。それらは、 myXML オブジェクトが持つ 2 つの book プロパティに対応する 2 つの XML オブジェクトです。

オブジェクト myXML..lastName は XMLList オブジェクトであり、 lastName という名前を持つすべての子孫プロパティを含んでいます。それらは、 myXML オブジェクトが持つ 2 つの lastName プロパティに対応する 2 つの XML オブジェクトです。

オブジェクト myXML.book.editor.lastName は XMLList オブジェクトであり、 myXML オブジェクトの book という子の editor という子の、 lastName という名前を持つすべての子を含んでいます。この場合、これは XML オブジェクトを 1 つだけ含んだ XMLList オブジェクトです(値が「 Case 」である lastName プロパティ)。

親ノードおよび子ノードへのアクセス

parent() メソッドは、XML オブジェクトの親を返します。

子リストでは、序数のインデックス値を指定することにより特定の子オブジェクトにアクセスできます。 例えば、XML オブジェクト myXML book という名前のプロパティが 2 つある場合、 book という名前の各子プロパティには、次のようにインデックス番号が対応しています。

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

特定の孫にアクセスするには、子の名前と孫の名前の両方に対してインデックス番号を指定します。

myXML.book[0].title[0]

ただし、 x.book[0] title という子が 1 つしかない場合は、次のようにインデックス参照を省略できます。

myXML.book[0].title

同じように、 x に book という子が 1 つしかなく、それに title オブジェクトが 1 つしか含まれない場合は、次のように両方のインデックス参照を省略できます。

myXML.book.title

変数や式で子の名前を指定してアクセスするには、次のように child() メソッドを使用します。

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

属性へのアクセス

XML オブジェクトまたは XMLList オブジェクトの属性にアクセスするには、次のコードのように @ シンボル(属性識別用の演算子)を使用します。

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

XML オブジェクトまたは XMLList オブジェクトが持つすべての属性にアクセスするには、次のコードのように、 @ シンボルにワイルドカードの * シンボルを付けます。

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

また、次のコードのように attribute() または attributes() メソッドを使用して、XML オブジェクトまたは XMLList オブジェクトが持つ特定の属性またはすべての属性にアクセスすることもできます。

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

メモ:属性へのアクセスには次のシンタックスを使用することもできます。その場合は下の例のようになります。

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

これらはいずれも employee.@id . employee.@id 構文が望ましい方法です。

属性またはエレメントの値によるフィルター処理

括弧演算子の ( および ) を使用すると、エレメント名または属性値を指定してエレメントをフィルター処理できます。例えば、次のような 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>

この場合、次の式はいずれも有効なコードです。

  • x.employee.(lastName == "McGee") :2 番目の employee ノード

  • x.employee.(lastName == "McGee").firstName :2 番目の employee ノードが持つ firstName プロパティ

  • x.employee.(lastName == "McGee").@id :2 番目の employee ノードが持つ id 属性の値

  • x.employee.(@id == 347) :最初の employee ノード

  • x.employee.(@id == 347).lastName :最初の employee ノードが持つ lastName プロパティ

  • x.employee.(@id > 300) :両方の employee プロパティを含んだ XMLList

  • x.employee.(position.toString().search("analyst") > -1) :両方の position プロパティを含んだ XMLList

存在しない属性またはエレメントを指定してフィルター処理を実行しようとすると、例外がスローされます。例えば、次のコード例では最後の行を実行しようとした時点でエラーが発生します。これは、2 番目の p エレメントに id 属性がないためです。

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

同じように、次のコード例では最後の行を実行しようとした時点でエラーが発生します。これは、2 番目の p エレメントに b プロパティがないためです。

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

これらのエラーを避けるには、次のコードのように、 attribute() メソッドおよび elements() メソッドを使用して、一致する属性またはエレメントを持つプロパティを識別します。

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'));

また、次のコードのように 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'));

for..in および for each..in ステートメントの使用

XMLList オブジェクトに対して繰り返し処理を実行する場合、ActionScript 3.0 では for..in ステートメントと for each..in ステートメントを使用できます。例えば、次のような XML オブジェクト myXML と XMLList オブジェクト myXML.item があるとします。XMLList オブジェクトの myXML.item は、XML オブジェクトの item という 2 つのノードで構成されています。

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>;

for..in ステートメントを使用して繰り返し処理を実行するには、次のようにします。

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

for each..in ステートメントを使用して繰り返し処理を実行するには、次のようにします。

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