Mokelab Blog

#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");

参考資料

Namespaces in XML 1.0 (Third Edition)

本サイトではサービス向上のため、Google Analyticsを導入しています。分析にはCookieを利用しています。