# 機能設計書: xmltree - XMLツリー生成・操作

## 1. 機能概要

### 1.1 目的
xmltreeモジュールは、XMLツリー構造の生成と操作のための機能を提供する。XMLノードの作成、子要素の追加・削除・置換、属性の操作、およびXML文字列への変換をサポートする。

### 1.2 機能範囲
- XMLノードの作成（要素、テキスト、コメント、CDATA、エンティティ）
- 子ノードの追加・挿入・削除・置換
- 属性の取得・設定
- XMLツリーの文字列変換
- XMLエスケープ処理
- ノードの検索とイテレーション

### 1.3 関連コンポーネント
- `parsexml` モジュール: 低レベルXMLパーサー
- `xmlparser` モジュール: 高レベルXMLパース
- `htmlparser` モジュール: HTML解析
- `strtabs` モジュール: 属性テーブル

## 2. データ構造

### 2.1 型定義

```nim
type
  XmlNode* = ref XmlNodeObj  ## XMLツリーノード参照型

  XmlNodeKind* = enum  ## XMLノードの種類
    xnText,            ## テキスト要素
    xnVerbatimText,    ## そのままのテキスト（エスケープなし）
    xnElement,         ## 0個以上の子を持つ要素
    xnCData,           ## CDATAノード
    xnEntity,          ## エンティティ (&thing;)
    xnComment          ## XMLコメント

  XmlAttributes* = StringTableRef  ## 属性のエイリアス（文字列→文字列マッピング）

  XmlNodeObj {.acyclic.} = object
    case k: XmlNodeKind
    of xnText, xnVerbatimText, xnComment, xnCData, xnEntity:
      fText: string
    of xnElement:
      fTag: string
      s: seq[XmlNode]
      fAttr: XmlAttributes
    fClientData: int  ## クライアント用データ
```

### 2.2 特徴
- **参照型**: `XmlNode`は参照型のため、変更は共有される
- **バリアントオブジェクト**: `k`フィールドによって内部構造が変化
- **非循環マーク**: `{.acyclic.}`でGCの循環参照チェックを省略
- **遅延属性初期化**: メモリ節約のため属性は必要時に初期化

### 2.3 定数

```nim
const xmlHeader* = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
```

## 3. 主要機能

### 3.1 ノード作成

#### コンストラクタ

| プロシージャ | 説明 | ソース位置 |
|-------------|------|-----------|
| `newElement` | xnElement ノードを作成 | 85-101 |
| `newText` | xnText ノードを作成 | 104-112 |
| `newVerbatimText` | xnVerbatimText ノードを作成 | 114-118 |
| `newComment` | xnComment ノードを作成 | 120-128 |
| `newCData` | xnCData ノードを作成 | 130-138 |
| `newEntity` | xnEntity ノードを作成 | 140-148 |

#### newXmlTree
```nim
proc newXmlTree*(tag: sink string, children: openArray[XmlNode],
                 attributes: XmlAttributes = nil): XmlNode
```
- **目的**: タグ、子ノード、属性を指定してXMLツリーを作成
- **ソース位置**: `lib/pure/xmltree.nim:150-176`

### 3.2 プロパティアクセス

#### テキスト・タグ

| プロシージャ | 説明 | 対象ノード種 |
|-------------|------|-------------|
| `text` | テキスト内容取得 | xnText, xnVerbatimText, xnComment, xnCData, xnEntity |
| `text=` | テキスト内容設定 | 同上 |
| `tag` | タグ名取得 | xnElement |
| `tag=` | タグ名設定 | xnElement |
| `innerText` | 再帰的にテキスト取得 | 全ノード |

- **ソース位置**: `lib/pure/xmltree.nim:178-305`

#### kind
```nim
proc kind*(n: XmlNode): XmlNodeKind {.inline.}
```
- **目的**: ノードの種類を返す
- **ソース位置**: `lib/pure/xmltree.nim:519-526`

### 3.3 子ノード操作

#### add
```nim
proc add*(father, son: XmlNode) {.inline.}          ## 1つの子を追加
proc add*(father: XmlNode, sons: openArray[XmlNode]) {.inline.}  ## 複数の子を追加
```
- **ソース位置**: `lib/pure/xmltree.nim:307-347`

#### insert
```nim
proc insert*(father, son: XmlNode, index: int) {.inline.}
proc insert*(father: XmlNode, sons: openArray[XmlNode], index: int) {.inline.}
```
- **目的**: 指定位置に子ノードを挿入
- **ソース位置**: `lib/pure/xmltree.nim:350-405`

#### delete
```nim
proc delete*(n: XmlNode, i: Natural)           ## インデックスで削除
proc delete*(n: XmlNode, slice: Slice[int])    ## スライスで削除
```
- **ソース位置**: `lib/pure/xmltree.nim:407-451`

#### replace
```nim
proc replace*(n: XmlNode, i: Natural, replacement: openArray[XmlNode])
proc replace*(n: XmlNode, slice: Slice[int], replacement: openArray[XmlNode])
```
- **目的**: 子ノードを置換
- **ソース位置**: `lib/pure/xmltree.nim:453-507`

#### len と []
```nim
proc len*(n: XmlNode): int {.inline.}          ## 子ノード数を返す
proc `[]`*(n: XmlNode, i: int): XmlNode {.inline.}  ## i番目の子を取得
```
- **ソース位置**: `lib/pure/xmltree.nim:509-543`

#### clear
```nim
proc clear*(n: var XmlNode)
```
- **目的**: すべての子ノードを再帰的に削除
- **ソース位置**: `lib/pure/xmltree.nim:545-570`

### 3.4 属性操作

```nim
proc attrs*(n: XmlNode): XmlAttributes {.inline.}        ## 属性取得
proc `attrs=`*(n: XmlNode, attr: XmlAttributes) {.inline.}  ## 属性設定
proc attrsLen*(n: XmlNode): int {.inline.}               ## 属性数取得
proc attr*(n: XmlNode, name: string): string             ## 特定属性取得
proc toXmlAttributes*(keyValuePairs: varargs[tuple[key, val: string]]): XmlAttributes
```
- **ソース位置**: `lib/pure/xmltree.nim:602-686`

### 3.5 イテレータ

```nim
iterator items*(n: XmlNode): XmlNode           ## 子ノードをイテレート
iterator mitems*(n: var XmlNode): var XmlNode  ## 変更可能なイテレーション
iterator pairs*(n: XmlNode): (int, XmlNode)    ## インデックス付きイテレーション
```
- **ソース位置**: `lib/pure/xmltree.nim:573-600`

### 3.6 XML文字列変換

#### escape
```nim
proc escape*(s: string): string
proc addEscaped*(result: var string, s: string)
```
- **目的**: XML特殊文字をエスケープ
- **変換**: `<` → `&lt;`, `>` → `&gt;`, `&` → `&amp;`, `"` → `&quot;`, `'` → `&apos;`
- **ソース位置**: `lib/pure/xmltree.nim:700-728`

#### $演算子
```nim
proc `$`*(n: XmlNode): string
```
- **目的**: XMLノードを整形された文字列に変換
- **ソース位置**: `lib/pure/xmltree.nim:736-797付近`

### 3.7 クライアントデータ

```nim
proc clientData*(n: XmlNode): int {.inline.}
proc `clientData=`*(n: XmlNode, data: int) {.inline.}
```
- **目的**: クライアント用の整数データを格納（HTMLパーサーで使用）
- **ソース位置**: `lib/pure/xmltree.nim:688-698`

## 4. 使用例

```nim
import std/xmltree

# 要素の作成
var g = newElement("myTag")
g.add newText("some text")
g.add newComment("this is comment")

var h = newElement("secondTag")
h.add newEntity("some entity")

# 属性付きツリーの作成
let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes
let k = newXmlTree("treeTag", [g, h], att)

echo $k
# 出力:
# <treeTag key1="first value" key2="second value">
#   <myTag>some text<!-- this is comment --></myTag>
#   <secondTag>&some entity;</secondTag>
# </treeTag>
```

## 5. コードリーディングガイド

### 5.1 推奨読解順序

1. **型定義** (40-68行目)
   - `XmlNode`, `XmlNodeKind`, `XmlAttributes`の構造

2. **コンストラクタ** (81-176行目)
   - `newElement`, `newText`, `newXmlTree`等

3. **プロパティ** (178-305行目)
   - `text`, `tag`, `innerText`

4. **子ノード操作** (307-570行目)
   - `add`, `insert`, `delete`, `replace`

5. **属性操作** (602-686行目)
   - `attrs`, `attr`, `toXmlAttributes`

6. **文字列変換** (700-800行目)
   - `escape`, `$`, `addImpl`

### 5.2 プログラム呼び出し階層図

```
newXmlTree(tag, children, attributes) [150行目]
├── newXmlNode(xnElement)
├── result.fTag = tag
├── result.s = children
└── result.fAttr = attributes

$node [文字列変換]
└── addImpl(result, n, indent, indWidth, addNewLines)
    ├── xnElement
    │   ├── '<' + fTag
    │   ├── 属性出力 (key="value")
    │   ├── 子ノード再帰処理
    │   └── '</' + fTag + '>'
    ├── xnText
    │   └── addEscaped(fText)
    ├── xnVerbatimText
    │   └── fText (エスケープなし)
    ├── xnCData
    │   └── '<![CDATA[' + fText + ']]>'
    ├── xnComment
    │   └── '<!-- ' + fText + ' -->'
    └── xnEntity
        └── '&' + fText + ';'
```

### 5.3 データフロー図

```
[コンストラクタ]
      │
      ▼
┌─────────────────────────────────────┐
│            XmlNode                   │
│  ┌─────────────────────────────┐    │
│  │    k: XmlNodeKind            │    │
│  ├─────────────────────────────┤    │
│  │ xnElement:                   │    │
│  │   fTag: string               │    │
│  │   s: seq[XmlNode]            │    │
│  │   fAttr: XmlAttributes       │    │
│  ├─────────────────────────────┤    │
│  │ xnText/xnComment/...:        │    │
│  │   fText: string              │    │
│  └─────────────────────────────┘    │
└──────────────────┬───────────────────┘
                   │
     ┌─────────────┼─────────────┐
     │             │             │
     ▼             ▼             ▼
 add/insert    attrs操作      $演算子
     │             │             │
     ▼             ▼             ▼
 子ノード追加  属性設定     XML文字列
```

### 5.4 読解のコツ

- **バリアントオブジェクト**: `case k: XmlNodeKind`で種類によって異なるフィールドを持つ
- **expect テンプレート**: ノード種類のアサーション（73-79行目）
- **遅延初期化**: 属性は`nil`で初期化され、使用時にのみ割り当て
- **インデント処理**: `addImpl`の`indent`と`indWidth`パラメータで制御

## 6. 関連ファイル一覧

| ファイルパス | 種別 | 役割 |
|-------------|------|------|
| `lib/pure/xmltree.nim` | ソース | メイン実装 |
| `lib/pure/strtabs.nim` | ソース | StringTableRef定義 |
| `lib/pure/strutils.nim` | ソース | 文字列処理 |
| `lib/pure/sequtils.nim` | ソース | シーケンス処理 |
| `lib/pure/macros.nim` | ソース | マクロサポート |

## 7. 設計上の考慮事項

### 7.1 メモリ効率
- 属性は遅延初期化（102行目コメント参照）
- `{.acyclic.}`で循環参照チェックを省略
- `sink`パラメータで不要なコピーを回避

### 7.2 出力形式
- `$`演算子は整形された（pretty-printed）XMLを生成
- 子ノードにテキストが含まれる場合は改行を抑制
- 空要素は`<tag />`形式で出力

### 7.3 xnVerbatimText
- バージョン1.3で追加
- エスケープなしでテキストを出力（HTMLの`<script>`タグ等に使用）
