# xml.document

> A module of xml's API.

`xml.document` — a small read-only tree built from `XmlReader` events.

API responses are small and are read by *path*: "every
`reservationSet/item/instancesSet/item`, and under each its `instanceType`".
That is awkward over a pull parser and natural over a tree, so `Document`
builds one — but flat, as parallel arrays indexed by node id, rather than as
recursive structs. A node is an element; its text is the concatenation of
its direct text children (whitespace-only runs between child elements are
dropped), which is the only text model an API response needs.

```mojo
var doc = Document.parse(body)
for item in doc.find_all(doc.root(), "reservationSet/item/instancesSet/item"):
    print(doc.child_text(item, "instanceId"), doc.find_text(item, "instanceState/name"))
```

Path segments match the *local* name, so a namespace prefix on the document
side never has to be spelled out. `*` matches any element.

## Structs

### `Document`

```mojo
struct Document
```

Implements: `Movable`, `Sized`

#### `__init__`

```mojo
def __init__(out self)
```

#### `parse`

```mojo
def parse(doc: String) -> Self
```

Parses a whole document. Raises on malformed XML or no root.

#### `__len__`

```mojo
def __len__(self) -> Int
```

Number of elements in the document.

#### `root`

```mojo
def root(self) -> Int
```

#### `name`

```mojo
def name(self, node: Int) -> String
```

The element's name as written, prefix included.

#### `text`

```mojo
def text(self, node: Int) -> String
```

The element's own text, entity-decoded.

#### `parent`

```mojo
def parent(self, node: Int) -> Int
```

#### `attr`

```mojo
def attr(self, node: Int, name: String, default: String = "") -> String
```

#### `children`

```mojo
def children(self, node: Int) -> List[Int]
```

#### `child`

```mojo
def child(self, node: Int, name: String) -> Int
```

The first child with local name `name`, or `NO_NODE`.

#### `child_text`

```mojo
def child_text(self, node: Int, name: String, default: String = "") -> String
```

#### `find_all`

```mojo
def find_all(self, node: Int, path: String) -> List[Int]
```

Every element reached from `node` by the `/`-separated `path`.

Each segment steps down one level and matches *all* children of that
name, so `a/b` yields every `b` under every `a`, in document order.

#### `find`

```mojo
def find(self, node: Int, path: String) -> Int
```

The first element `find_all` would return, or `NO_NODE`.

#### `find_text`

```mojo
def find_text(self, node: Int, path: String, default: String = "") -> String
```

## Aliases

### `NO_NODE`

```mojo
comptime NO_NODE = -1
```
