#32 AndroidのXMLのxmlnsとは?
AndroidのレイアウトXMLなどには、次のようにルート要素にxmlnsの指定がついています。
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
URLが書いてあるので、雰囲気だとDTDが取得できそうです。curlで取ってきてみましょう。
% curl http://schemas.android.com/apk/res/android
curl: (6) Could not resolve host: schemas.android.com
そもそもschemas.android.com
というホスト名知らないよと言われてしまいました。定義を読み込んでいる訳ではなさそうです。
XMLの名前空間
ここからはAndroidというよりXMLの話になります。XMLの要素名や属性名に対し、名前空間(namespace)をつけることができます。
XMLの名前空間はURI(Uniform Resource
Identifier)で指定します。http://schemas.android.com/apk/res/android
は
URLではなくURIだったことになります。
名前空間となる文字列を属性とかの前に毎回つけると読みにくくなるので、XMLでは接頭辞(prefix)を使います。
xmlns:android="http://schemas.android.com/apk/res/android"
は、「androidという接頭辞はこのURIになりますよ」という対応を指定していたことになります。
「androidという名前空間の定義はここですよ」という意味ではありません。
つまり、レイアウトXMLを次のように変更しても同じ意味となります。Android Studioもエラー扱いしません。
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:moke="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
moke:layout_width="match_parent"
moke:layout_height="match_parent"
tools:context=".MainActivity">
XMLの名前空間が単なる文字列だということがわかったところで、次は扱い方です。JavaScriptで、AndroidのレイアウトXMLをパースしandroid:layout_width
の値を取得してみます。
xml = `<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"></androidx.constraintlayout.widget.ConstraintLayout>`
// パーサー作って
p = new DOMParser()
// パースして
d = p.parseFromString(xml, 'text/xml')
// 要素とってきて
root = d.getElementsByTagName('androidx.constraintlayout.widget.ConstraintLayout')[0]
// 名前空間を指定した上で、属性をとってくる
console.log(root.getAttributeNS('http://schemas.android.com/apk/res/android', 'layout_width'))
>> match_parent
getAttributeNS
で、名前空間もセットで指定します。この時指定するのは接頭辞ではなくURIです。
Androidでは、SDKの中でURIを使って属性を取っている箇所があります(例)。
private static final String ANDROID_RESOURCES
= "http://schemas.android.com/apk/res/android"
usesSplitName = attrs.getAttributeValue(ANDROID_RESOURCES, "name");