Programming Field

DOMの基本構造

スポンサーリンク

DOMではDocument、Nodeなどのインターフェイスを元に文書(ドキュメント)を定義する構造であり、いくつかのインターフェイスが子要素を持つことで木構造を成します。

DOMのツリー構造

例えば以下のようなXMLを考えます。

[XML]

<root myAttr1="attr" myAttr2="foo">
    <myElement myAttr3="val" myAttr4="hoge">text</myElement>
    <myElement2 />
</root>

このXMLをDOMに当てはめると以下の構造が考えられます。(改行やインデントによるスペースのTextノードは省略します)

documentElementの定義は「親がdocumentである要素」であり、他にNodeが無ければchildNodes[0]と同義です(ブラウザーがサポートしていればfirstElementChildと同じです)。

基本的には、XMLのタグはすべて「Element」となり、Elementに定義される属性(Attr)のまとまりは「attributes」、子要素(ElementTextCDATASectionなど)のまとまりは「childNodes」に入ります。また、XMLやHTMLなどは必ず「Document」がトップレベルの親となります。なお、Documentインターフェイスが持つ子要素としてのElementDocumentTypeは最大1つまでと定められています。

DocumentTypeの制限は「DOM Level2 Core Specification」より定義。

また、ElementAttributeなど、多くのインターフェイスはNodeインターフェイスから派生しています。以下はインターフェイスの派生状況をツリー表示したものです(一部のみ掲載しています)。

※1 これらのインターフェイスは「DOM Level 3 Core Specification」(以下DOM3)で新たに登場したインターフェイスです。
※2 これらのインターフェイスはDOM4にて削除されています。
※3 ProcessingInstructionインターフェイスはDOM3まではNodeインターフェイスを直接継承していましたが、DOM4ではTextインターフェイスを直接継承する形になっています。
※4 AttrインターフェイスはDOM4では独立したインターフェイスに変更となっていますが、DOM3まで、およびDOM4.1のDraft(2018/02/01)時点ではNodeインターフェイスを継承しています。
※5 これらのインターフェイスはDOM4で新たに登場したインターフェイスです。

スポンサーリンク

Nodeの子要素を調べる

上記のように、ElementTextの要素はNodeインターフェイスのプロパティやメソッドを使用できます。そのため、childNodesを使ってNodeの一覧を取得した場合、その子要素がElementTextであるかなどを判定する場合は、Nodeで定義されている「nodeType」を使って判定することができます。(逆に、childNodesの中身はすべてNodeとなっているので、型に厳密な言語では目的の型に適切に変換を行う必要があります。)

[JavaScript]

var element, node;

// element には既に Element の参照が入っているとする
for (var i = 0; i < element.childNodes.length; i++) {
    node = element.childNodes[i];
    if (node.nodeType === 1) { // 1 == ELEMENT_NODE
        // node は Element なので tagName などが使える
    } else if (node.nodeType === 3) { // 3 == TEXT_NODE
        // node は Text なので nodeValue にテキストが入っている
    }
    ...
}
[VB.NET] (System.Xml ライブラリ使用)

Imports System.Xml
Dim element As XmlElement, node As XmlNode

' element には既に XmlElement の参照が入っているとする
For Each node In element.ChildNodes
    Select Case node.NodeType
        Case XmlNodeType.Element
            ' node は XmlElement に変換して Attributes などが使用可能
            ' (※ TagName プロパティは存在しないので Name を使う)
        Case XmlNodeType.Text
            ' node は XmlText であり、(node.)Value プロパティにはテキストが入っている
        ...
    End Select
Next node

※ 言語や環境によって、インスタンスの型チェック(JavaScriptではinstanceof演算子、VB.NETではTypeOf演算子)を使ってノードの種類を調べることもできます。ただし一部のブラウザー上では「Element」などの名前が利用できない場合があるため、それらを意識する場合はnodeTypeでの判定を行う方が確実です。
※ DOM4にて、NodeListiterable<Node>の宣言が付加されるようになりました。これはentriesforEachkeys、およびvaluesの各メソッド(および@@iterator)が使用できるということを表しています。ただしDOM4に対応していないような一部のブラウザーでは利用できない可能性が高いため注意が必要です。

属性を表す「Attr」はNodeの子要素としては現れず、代わりにElement(DOM3まではNode)に定義されているattributesを用います。attributesは、通常の配列を表すNodeListインターフェイスの代わりに、名前付き配列(マップ)であるNamedNodeMapインターフェイスが使用されています。したがって、「myAttr1」という属性を取得したい場合は

[JavaScript]
var attr = element.attributes.getNamedItem("myAttr1");

のように「getNamedItem」メソッドでAttrインターフェイスを取得することができます。

※ 上記の例で「myAttr1」が「element」の属性として定義されていない場合は、attrにnullが返ります。また、(DOM3までは)elementがElementでない場合はattributesnullとなるためエラーになります。(仕様)
NamedNodeMap(attributesを含む)はNodeListではありません。そのためDOM4やDOM4.1(2018/02/01時点)においてもforEachなどを使用することはできません。
※ DOM4時点での仕様では、NamedNodeMapの「getNamedItem」メソッドはNodeを返すことになっていますが、AttrNodeでは無くなっているため、この定義は厳密には誤りになり、DOM4.1で修正される予定です(参考: [w3c/dom] Attr and NamedNodeMap in DOM4 are inconsistent - Issue #4)。

最終更新日: 2018/02/20