XMLをいじっていて不思議な現象が。下記のようなXMLを定義します。
var xml:XML =
<itemlist>
<itemGroup name=”X”>
<itemGroup name=”XX”>
<itemGroup name=”XXX”>
<item name=”XXX001″ />
<item name=”XXX002″ />
<item name=”XXX003″ />
<item name=”XXX004″ />
<item name=”XXX005″ />
</itemGroup>
</itemGroup>
<item name=”X-001″ />
<item name=”X-002″ />
</itemGroup>
</itemlist>;
この中のitemエレメントで@name=”XX001″のデータの親を参照すると、下記のようになります。これは問題なし。
trace(xml..item.(@name==”XXX001″).parent());
—-
<itemGroup name=”XXX”>
<item name=”XXX001″/>
<item name=”XXX002″/>
<item name=”XXX003″/>
<item name=”XXX004″/>
<item name=”XXX005″/>
</itemGroup>
次に同じ条件でitemエレメントを検索して、それを別XMLの子として追加します。
var xmlList:XMLList = xml..item.(@name==”XXX001″);
var xml2:XML = new XML(“<top></top>”)
for each (var item:XML in xmlList) {
xml2.appendChild(item);
}
xml2に対して、itemエレメントで@name=”XX001″のデータの親を参照すると、下記のようになります。これも問題なし。
trace(xml2..item.(@name==”XXX001″).parent());
—-
<top>
<item name=”XXX001″/>
</top>
この後に、元々のXML(xml)に対して、同じく親を参照すると・・・
trace(xml..item.(@name==”XXX001″).parent());
—-
<top>
<item name=”XXX001″/>
</top>
と、別XMLの親を参照してしまいます。該当エレメントを別XMLに追加してしまうと、元XMLの該当エレメントの参照も変わってしまうようなのです。
これってどういうことなんでしょうね???もっとも別XMLにしたいなら、XML.copy()で複製を作れって話ではあるんですけけど、ちょっと納得いかない感じです。
文字通り、特定のエレメントから遡って、全ての親エレメント名を取得するための関数を書きました。XMLは下層に向かっての処理はいろいろあるけど、上層に向かっての処理は少ない気がする。前提として、XMLは上から下に向かって使うものなのか? いや、そんなことないよね。単に階層化されたデータな訳だから。
//—————————
// 親ノード名取得(再帰)
//—————————
function getParentName_xml(xml:XML,array:Array):void
{
if (xml.parent() != undefined)
{
array.unshift(xml.parent().name());
getParentName_xml(xml.parent(),array);
}
}
前回の件みたいに単なる見落としの可能性もあるので、もっと簡便な方法を知ってる方は教えてください。
var resultList:XMLList = xml..aa;
と出来るのですが、このaaが文字列の場合にはどうすればいいか?
何かメソッドがあるはずだと探しまくって発見したのが、XML.descendants()でした。
var resultList:XMLList = xml.descendants(“aa”);
普段XMLを使う場合は、UTF-8で作成するので意識したことなかったけど、今回使用するRSSがたまたまShift-JISでそのままでは2バイト文字が文字化け。System.useCodePage を使ってもダメで、どうしたものかと検索したら見つかりました。
XMLのURLLoaderのデータフォーマットをURLLoaderDataFormat.BINARY として、バイナリでロードした後にByteArray.readMultiByteでShift-JIS >> UTF-8 への変換をすればOKでした。厳密には、EUC-JPでは別に対処が必要とかあるみたいですけど、今回はShift-JISが変換できればいいので(笑)。下記のサイトを参考にしました。感謝。
AS3.0では名前空間を持つXMLは、名前空間を使わないとアクセスできない。で、名前空間を指定した後クリアしていたんだけど、そのクリア方法に問題在り。nullでなくundefinedを使うこと。
nullだと次にXMLを使ったときに、namespaceの初期値が xmlns=”null” になってしまう。わからなくてさんざん悩んだ。ざっくりだけど、該当部分だけ貼っておきます。一番最後が問題だった箇所です。
//名前空間を抽出・保存(接頭辞で指定)
for (var i:int = 0; i<doc_xml.namespaceDeclarations().length; i++) {
switch (doc_xml.namespaceDeclarations()[i].prefix) {
case “” :
var ns_def:Namespace = new Namespace(doc_xml.namespace(doc_xml.namespaceDeclarations()[i].prefix));
break;
case “dc” :
var dc:Namespace = new Namespace(doc_xml.namespace(doc_xml.namespaceDeclarations()[i].prefix));
break;
case “rdf” :
var rdf:Namespace = new Namespace(doc_xml.namespace(doc_xml.namespaceDeclarations()[i].prefix));
break;
}
}
//名前空間のデフォルト値を設定
default xml namespace = ns_def;
//(XMLの処理)
//名前空間のデフォルト値を設定解除(ここはundefinedで。nullは不可)
default xml namespace = undefined;
xmlで引っかかった点。
テキストノードを表示する処理を書いていて、字数制限が必要でString処理を挟んだら動かなくなった。テキストノードに値がないので、空白かな〜と思っても判定できず。調べてみたら、テキストノードに値がない場合の戻り値はundefinedだった。
こんな感じでテスト。
var test_xml:XML =
<itemlist>
<msg>おはよう</msg>
<msg></msg>
<msg>こんにちは</msg>
<msg />
<msg>おやすみ</msg>
</itemlist>;
for each(var item:XML in test_xml.msg) {
trace(“text=”+item.text(),(item.text() == “”),(item.text() == null),(item.text() == undefined))
}
——出力結果
text=おはよう false false false
text= false false true
text=こんにちは false false false
text= false false true
text=おやすみ false false false
AS,Objective-C,Javascript,その他諸々の備忘録