> For the complete documentation index, see [llms.txt](https://docs.apryse.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apryse.com/core/create/document-creation-api/traverse-the-content-tree.md).

# Traverse the content tree

Use the document creation API to traverse the content tree programmatically for docs.

Traversing the content tree, or, visiting every node or page in a hierarchical data structure makes the content tree stay inspectable until you paginate. This allows you to generate content first and decide its style afterwards which is useful for applying rules that depend on the finished document, such as banding every second row or restyling every heading.

## Iterate children

`GetContentNodeIterator` returns an iterator over the direct children of a node. Every child is a `ContentElement`.

{% tabs %}
{% tab title="C#" %}
{% code lineNumbers="true" %}

```csharp
for (ContentNodeIterator itr = node.GetContentNodeIterator(); itr.HasNext(); itr.Next())
{
    ContentElement el = itr.Current();
    // ... inspect el ...
}
```

{% endcode %}
{% endtab %}

{% tab title="C++" %}
{% code lineNumbers="true" %}

```cpp
for (ContentNodeIterator itr = node.GetContentNodeIterator(); itr.HasNext(); itr.Next())
{
    ContentElement el = itr.Current();
    // ... inspect el ...
}
```

{% endcode %}
{% endtab %}

{% tab title="Go" %}
{% code lineNumbers="true" %}

```go
for itr := node.GetContentNodeIterator(); itr.HasNext(); itr.Next() {
    el := itr.Current()
    // ... inspect el ...
}
```

{% endcode %}
{% endtab %}

{% tab title="Java" %}
{% code lineNumbers="true" %}

```java
for (ContentNodeIterator itr = node.getContentNodeIterator(); itr.hasNext(); itr.next()) {
    ContentElement el = itr.current();
    // ... inspect el ...
}
```

{% endcode %}
{% endtab %}

{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```javascript
const itr = await node.getContentNodeIterator();
while (await itr.hasNext()) {
    const el = await itr.current();
    await itr.next();
    // ... inspect el ...
}
```

{% endcode %}
{% endtab %}

{% tab title="Obj-C" %}
{% code lineNumbers="true" %}

```objectivec
PTContentNodeIterator* itr = [node GetContentNodeIterator];
for (; [itr HasNext]; [itr Next])
{
    PTContentElement* el = [itr Current];
    // ... inspect el ...
}
```

{% endcode %}
{% endtab %}

{% tab title="PHP" %}
{% code lineNumbers="true" %}

```php
for ($itr = $node->GetContentNodeIterator(); $itr->HasNext(); $itr->Next()) {
    $el = $itr->Current();
    // ... inspect el ...
}
```

{% endcode %}
{% endtab %}

{% tab title="Python" %}
{% code lineNumbers="true" %}

```python
itr = node.GetContentNodeIterator()
while itr.HasNext():
    el = itr.Current()
    # ... inspect el ...
    itr.Next()
```

{% endcode %}
{% endtab %}

{% tab title="Ruby" %}
{% code lineNumbers="true" %}

```ruby
itr = node.GetContentNodeIterator()
while itr.HasNext()
  el = itr.Current()
  # ... inspect el ...
  itr.Next()
end
```

{% endcode %}
{% endtab %}
{% endtabs %}

## Identify elements

A content element exposes one conversion method per concrete type. In C++, these return an `ElementRef`, which supports the safe-bool idiom and is dereferenced with `->`. In the other languages, they return the object itself, or a null value when the element is not of that type.

{% tabs %}
{% tab title="C#" %}
{% code lineNumbers="true" %}

```csharp
Paragraph para = el.AsParagraph();
if (para != null)
    para.GetTextStyledElement().SetFontSize(11);
```

{% endcode %}
{% endtab %}

{% tab title="C++" %}
{% code lineNumbers="true" %}

```cpp
if (ElementRef<Paragraph> para = el.AsParagraph())
    para->GetTextStyledElement().SetFontSize(11);
```

{% endcode %}
{% endtab %}

{% tab title="Go" %}
{% code lineNumbers="true" %}

```go
para := el.AsParagraph()
if para.Swigcptr() != 0 {
    para.GetTextStyledElement().SetFontSize(11)
}
```

{% endcode %}
{% endtab %}

{% tab title="Java" %}
{% code lineNumbers="true" %}

```java
Paragraph para = el.asParagraph();
if (para != null)
    para.getTextStyledElement().setFontSize(11);
```

{% endcode %}
{% endtab %}

{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```javascript
const para = await el.asParagraph();
if (para !== null) {
    (await para.getTextStyledElement()).setFontSize(11);
}
```

{% endcode %}
{% endtab %}

{% tab title="Obj-C" %}
{% code lineNumbers="true" %}

```objectivec
PTParagraph* para = [el AsParagraph];
if (para != nil)
    [[para GetTextStyledElement] SetFontSize:11];
```

{% endcode %}
{% endtab %}

{% tab title="PHP" %}
{% code lineNumbers="true" %}

```php
$para = $el->AsParagraph();
if ($para != null)
    $para->GetTextStyledElement()->SetFontSize(11);
```

{% endcode %}
{% endtab %}

{% tab title="Python" %}
{% code lineNumbers="true" %}

```python
para = el.AsParagraph()
if para is not None:
    para.GetTextStyledElement().SetFontSize(11)
```

{% endcode %}
{% endtab %}

{% tab title="Ruby" %}
{% code lineNumbers="true" %}

```ruby
para = el.AsParagraph()
if !para.nil?
  para.GetTextStyledElement().SetFontSize(11)
end
```

{% endcode %}
{% endtab %}
{% endtabs %}

<table data-search="false"><thead><tr><th>Method</th><th>Converts to</th></tr></thead><tbody><tr><td><code>AsContentNode</code></td><td>Any node that has children</td></tr><tr><td><code>AsParagraph</code></td><td><code>Paragraph</code></td></tr><tr><td><code>AsTextRun</code></td><td><code>TextRun</code></td></tr><tr><td><code>AsPageNumber</code></td><td><code>PageNumber</code></td></tr><tr><td><code>AsTable</code>, <code>AsTableRow</code>, <code>AsTableCell</code></td><td>Table elements</td></tr><tr><td><code>AsList</code>, <code>AsListItem</code></td><td>List elements</td></tr><tr><td><code>AsShape</code>, <code>AsChart</code>, <code>AsFloat</code></td><td>Shape, chart and float</td></tr></tbody></table>

{% hint style="info" %}
**Info**

In C++, dereferencing an invalid `ElementRef` throws an error. Always test it first.
{% endhint %}

## Walk the whole tree

Recursing through `AsContentNode` visits every element in the document, whatever its nesting depth - including content inside table cells, list items, shape text boxes and floats.

{% tabs %}
{% tab title="C#" %}
{% code lineNumbers="true" %}

```csharp
// Highlight every second text run and outline every table cell.
static bool RestyleContentTree(ContentNode node, bool highlight)
{
    for (ContentNodeIterator itr = node.GetContentNodeIterator(); itr.HasNext(); itr.Next())
    {
        ContentElement el = itr.Current();

        TextRun textRun = el.AsTextRun();
        if (textRun != null)
        {
            if (highlight)
            {
                TextStyledElement style = textRun.GetTextStyledElement();
                style.SetBold(true);
                style.SetBackgroundColor(255, 245, 180);
            }
            highlight = !highlight;
            continue;
        }

        TableCell cell = el.AsTableCell();
        if (cell != null)
            cell.SetBorder(0.5, 150, 150, 150);

        ContentNode child = el.AsContentNode();
        if (child != null)
            highlight = RestyleContentTree(child, highlight);
    }
    return highlight;
}

RestyleContentTree(doc, false);
```

{% endcode %}
{% endtab %}

{% tab title="C++" %}
{% code lineNumbers="true" %}

```cpp
// Highlight every second text run and outline every table cell.
void RestyleContentTree(ContentNode node, bool& highlight)
{
    for (ContentNodeIterator itr = node.GetContentNodeIterator(); itr.HasNext(); itr.Next())
    {
        ContentElement el = itr.Current();

        if (ElementRef<TextRun> text_run = el.AsTextRun())
        {
            if (highlight)
            {
                TextStyledElement style = text_run->GetTextStyledElement();
                style.SetBold(true);
                style.SetBackgroundColor(255, 245, 180);
            }
            highlight = !highlight;
            continue;
        }

        if (ElementRef<TableCell> cell = el.AsTableCell())
            cell->SetBorder(0.5, 150, 150, 150);

        if (ElementRef<ContentNode> child = el.AsContentNode())
            RestyleContentTree(*child, highlight);
    }
}

bool highlight = false;
RestyleContentTree(doc, highlight);
```

{% endcode %}
{% endtab %}

{% tab title="Go" %}
{% code lineNumbers="true" %}

```go
// Highlight every second text run and outline every table cell.
func restyleContentTree(node ContentNode, highlight bool) bool {
    for itr := node.GetContentNodeIterator(); itr.HasNext(); itr.Next() {
        el := itr.Current()

        if textRun := el.AsTextRun(); textRun.Swigcptr() != 0 {
            if highlight {
                style := textRun.GetTextStyledElement()
                style.SetBold(true)
                style.SetBackgroundColor(255, 245, 180)
            }
            highlight = !highlight
            continue
        }

        if cell := el.AsTableCell(); cell.Swigcptr() != 0 {
            cell.SetBorder(0.5, 150, 150, 150)
        }

        if child := el.AsContentNode(); child.Swigcptr() != 0 {
            highlight = restyleContentTree(child, highlight)
        }
    }
    return highlight
}

restyleContentTree(doc, false)
```

{% endcode %}
{% endtab %}

{% tab title="Java" %}
{% code lineNumbers="true" %}

```java
// Highlight every second text run and outline every table cell.
static boolean restyleContentTree(ContentNode node, boolean highlight) throws PDFNetException {
    for (ContentNodeIterator itr = node.getContentNodeIterator(); itr.hasNext(); itr.next()) {
        ContentElement el = itr.current();

        TextRun textRun = el.asTextRun();
        if (textRun != null) {
            if (highlight) {
                TextStyledElement style = textRun.getTextStyledElement();
                style.setBold(true);
                style.setBackgroundColor(255, 245, 180);
            }
            highlight = !highlight;
            continue;
        }

        TableCell cell = el.asTableCell();
        if (cell != null)
            cell.setBorder(0.5, 150, 150, 150);

        ContentNode child = el.asContentNode();
        if (child != null)
            highlight = restyleContentTree(child, highlight);
    }
    return highlight;
}

restyleContentTree(doc, false);
```

{% endcode %}
{% endtab %}

{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```javascript
// Highlight every second text run and outline every table cell.
const restyleContentTree = async (node, highlight) => {
    const itr = await node.getContentNodeIterator();
    while (await itr.hasNext()) {
        const el = await itr.current();
        await itr.next();

        const textRun = await el.asTextRun();
        if (textRun !== null) {
            if (highlight) {
                const style = await textRun.getTextStyledElement();
                style.setBold(true);
                style.setBackgroundColor(255, 245, 180);
            }
            highlight = !highlight;
            continue;
        }

        const cell = await el.asTableCell();
        if (cell !== null) {
            cell.setBorder(0.5, 150, 150, 150);
        }

        const child = await el.asContentNode();
        if (child !== null) {
            highlight = await restyleContentTree(child, highlight);
        }
    }
    return highlight;
};

await restyleContentTree(doc, false);
```

{% endcode %}
{% endtab %}

{% tab title="Obj-C" %}
{% code lineNumbers="true" %}

```objectivec
// Highlight every second text run and outline every table cell.
BOOL RestyleContentTree(PTContentNode* node, BOOL highlight)
{
    PTContentNodeIterator* itr = [node GetContentNodeIterator];
    for (; [itr HasNext]; [itr Next])
    {
        PTContentElement* el = [itr Current];

        PTTextRun* text_run = [el AsTextRun];
        if (text_run != nil)
        {
            if (highlight)
            {
                PTTextStyledElement* style = [text_run GetTextStyledElement];
                [style SetBold:YES];
                [style SetBackgroundColor:255 green:245 blue:180];
            }
            highlight = !highlight;
            continue;
        }

        PTTableCell* cell = [el AsTableCell];
        if (cell != nil)
            [cell SetBorder:0.5 red:150 green:150 blue:150];

        PTContentNode* child = [el AsContentNode];
        if (child != nil)
            highlight = RestyleContentTree(child, highlight);
    }
    return highlight;
}

RestyleContentTree(doc, NO);
```

{% endcode %}
{% endtab %}

{% tab title="PHP" %}
{% code lineNumbers="true" %}

```php
// Highlight every second text run and outline every table cell.
function RestyleContentTree($node, $highlight)
{
    for ($itr = $node->GetContentNodeIterator(); $itr->HasNext(); $itr->Next()) {
        $el = $itr->Current();

        $text_run = $el->AsTextRun();
        if ($text_run != null) {
            if ($highlight) {
                $style = $text_run->GetTextStyledElement();
                $style->SetBold(true);
                $style->SetBackgroundColor(255, 245, 180);
            }
            $highlight = !$highlight;
            continue;
        }

        $cell = $el->AsTableCell();
        if ($cell != null)
            $cell->SetBorder(0.5, 150, 150, 150);

        $child = $el->AsContentNode();
        if ($child != null)
            $highlight = RestyleContentTree($child, $highlight);
    }
    return $highlight;
}

RestyleContentTree($doc, false);
```

{% endcode %}
{% endtab %}

{% tab title="Python" %}
{% code lineNumbers="true" %}

```python
# Highlight every second text run and outline every table cell.
def restyle_content_tree(node, highlight):
    itr = node.GetContentNodeIterator()
    while itr.HasNext():
        el = itr.Current()
        itr.Next()

        text_run = el.AsTextRun()
        if text_run is not None:
            if highlight:
                style = text_run.GetTextStyledElement()
                style.SetBold(True)
                style.SetBackgroundColor(255, 245, 180)
            highlight = not highlight
            continue

        cell = el.AsTableCell()
        if cell is not None:
            cell.SetBorder(0.5, 150, 150, 150)

        child = el.AsContentNode()
        if child is not None:
            highlight = restyle_content_tree(child, highlight)
    return highlight

restyle_content_tree(doc, False)
```

{% endcode %}
{% endtab %}

{% tab title="Ruby" %}
{% code lineNumbers="true" %}

```ruby
# Highlight every second text run and outline every table cell.
def restyle_content_tree(node, highlight)
  itr = node.GetContentNodeIterator()
  while itr.HasNext()
    el = itr.Current()
    itr.Next()

    text_run = el.AsTextRun()
    if !text_run.nil?
      if highlight
        style = text_run.GetTextStyledElement()
        style.SetBold(true)
        style.SetBackgroundColor(255, 245, 180)
      end
      highlight = !highlight
      next
    end

    cell = el.AsTableCell()
    cell.SetBorder(0.5, 150, 150, 150) if !cell.nil?

    child = el.AsContentNode()
    highlight = restyle_content_tree(child, highlight) if !child.nil?
  end
  highlight
end

restyle_content_tree(doc, false)
```

{% endcode %}
{% endtab %}
{% endtabs %}

<figure><img src="https://3779731113-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fziw3GiL98Xfj63F3He8h%2Fuploads%2Fs3bWh7rz7JYYYSuWGCkY%2Fcontent_tree_walk.png?alt=media&amp;token=92c9f84e-edf5-48b6-9f8d-33466842b1e2" alt=""><figcaption></figcaption></figure>

A `FlowDocument` is itself a `ContentNode`, so passing the document walks the entire tree.

## Restyle just-created content

Traversal is also handy for a narrow scope, such as recoloring the header row you have only just built.

{% tabs %}
{% tab title="C#" %}
{% code lineNumbers="true" %}

```csharp
// Make every paragraph in the header row white.
for (ContentNodeIterator cellItr = headerRow.GetContentNodeIterator();
        cellItr.HasNext(); cellItr.Next())
{
    TableCell cell = cellItr.Current().AsTableCell();
    if (cell == null) continue;

    for (ContentNodeIterator paraItr = cell.GetContentNodeIterator();
            paraItr.HasNext(); paraItr.Next())
    {
        Paragraph para = paraItr.Current().AsParagraph();
        if (para != null)
            para.GetTextStyledElement().SetTextColor(255, 255, 255);
    }
}
```

{% endcode %}
{% endtab %}

{% tab title="C++" %}
{% code lineNumbers="true" %}

```cpp
// Make every paragraph in the header row white.
for (ContentNodeIterator cell_itr = header_row.GetContentNodeIterator();
        cell_itr.HasNext(); cell_itr.Next())
{
    if (ElementRef<TableCell> cell = cell_itr.Current().AsTableCell())
    {
        for (ContentNodeIterator para_itr = cell->GetContentNodeIterator();
                para_itr.HasNext(); para_itr.Next())
        {
            if (ElementRef<Paragraph> para = para_itr.Current().AsParagraph())
                para->GetTextStyledElement().SetTextColor(255, 255, 255);
        }
    }
}
```

{% endcode %}
{% endtab %}

{% tab title="Go" %}
{% code lineNumbers="true" %}

```go
// Make every paragraph in the header row white.
for cellItr := headerRow.GetContentNodeIterator(); cellItr.HasNext(); cellItr.Next() {
    cell := cellItr.Current().AsTableCell()
    if cell.Swigcptr() == 0 {
        continue
    }

    for paraItr := cell.GetContentNodeIterator(); paraItr.HasNext(); paraItr.Next() {
        para := paraItr.Current().AsParagraph()
        if para.Swigcptr() != 0 {
            para.GetTextStyledElement().SetTextColor(255, 255, 255)
        }
    }
}
```

{% endcode %}
{% endtab %}

{% tab title="Java" %}
{% code lineNumbers="true" %}

```java
// Make every paragraph in the header row white.
for (ContentNodeIterator cellItr = headerRow.getContentNodeIterator();
        cellItr.hasNext(); cellItr.next()) {
    TableCell cell = cellItr.current().asTableCell();
    if (cell == null) continue;

    for (ContentNodeIterator paraItr = cell.getContentNodeIterator();
            paraItr.hasNext(); paraItr.next()) {
        Paragraph para = paraItr.current().asParagraph();
        if (para != null)
            para.getTextStyledElement().setTextColor(255, 255, 255);
    }
}
```

{% endcode %}
{% endtab %}

{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```javascript
// Make every paragraph in the header row white.
const cellItr = await headerRow.getContentNodeIterator();
while (await cellItr.hasNext()) {
    const cell = await (await cellItr.current()).asTableCell();
    if (cell !== null) {
        const paraItr = await cell.getContentNodeIterator();
        while (await paraItr.hasNext()) {
            const para = await (await paraItr.current()).asParagraph();
            if (para !== null) {
                (await para.getTextStyledElement()).setTextColor(255, 255, 255);
            }
            await paraItr.next();
        }
    }
    await cellItr.next();
}
```

{% endcode %}
{% endtab %}

{% tab title="Obj-C" %}
{% code lineNumbers="true" %}

```objectivec
// Make every paragraph in the header row white.
PTContentNodeIterator* cell_itr = [header_row GetContentNodeIterator];
for (; [cell_itr HasNext]; [cell_itr Next])
{
    PTTableCell* cell = [[cell_itr Current] AsTableCell];
    if (cell == nil) continue;

    PTContentNodeIterator* para_itr = [cell GetContentNodeIterator];
    for (; [para_itr HasNext]; [para_itr Next])
    {
        PTParagraph* para = [[para_itr Current] AsParagraph];
        if (para != nil)
            [[para GetTextStyledElement] SetTextColor:255 green:255 blue:255];
    }
}
```

{% endcode %}
{% endtab %}

{% tab title="PHP" %}
{% code lineNumbers="true" %}

```php
// Make every paragraph in the header row white.
for ($cell_itr = $header_row->GetContentNodeIterator();
        $cell_itr->HasNext(); $cell_itr->Next()) {
    $cell = $cell_itr->Current()->AsTableCell();
    if ($cell == null) continue;

    for ($para_itr = $cell->GetContentNodeIterator();
            $para_itr->HasNext(); $para_itr->Next()) {
        $para = $para_itr->Current()->AsParagraph();
        if ($para != null)
            $para->GetTextStyledElement()->SetTextColor(255, 255, 255);
    }
}
```

{% endcode %}
{% endtab %}

{% tab title="Python" %}
{% code lineNumbers="true" %}

```python
# Make every paragraph in the header row white.
cell_itr = header_row.GetContentNodeIterator()
while cell_itr.HasNext():
    cell = cell_itr.Current().AsTableCell()
    cell_itr.Next()
    if cell is None:
        continue

    para_itr = cell.GetContentNodeIterator()
    while para_itr.HasNext():
        para = para_itr.Current().AsParagraph()
        if para is not None:
            para.GetTextStyledElement().SetTextColor(255, 255, 255)
        para_itr.Next()
```

{% endcode %}
{% endtab %}

{% tab title="Ruby" %}
{% code lineNumbers="true" %}

```ruby
# Make every paragraph in the header row white.
cell_itr = header_row.GetContentNodeIterator()
while cell_itr.HasNext()
  cell = cell_itr.Current().AsTableCell()
  cell_itr.Next()
  next if cell.nil?

  para_itr = cell.GetContentNodeIterator()
  while para_itr.HasNext()
    para = para_itr.Current().AsParagraph()
    para.GetTextStyledElement().SetTextColor(255, 255, 255) if !para.nil?
    para_itr.Next()
  end
end
```

{% endcode %}
{% endtab %}
{% endtabs %}

## Read content back

Traversal is not only for styling. The getters on text runs, tables, and sections let you inspect a document you have assembled, to compute a summary, run a validation pass, or log its structure.

## Notes

* Traversal reflects the tree **as built**. Line breaks, page breaks and page numbers are resolved during pagination and are not visible beforehand.
* Iterators visit direct children only; recurse through `AsContentNode` to go deeper.

## Further Reading

* [Tables](/core/create/document-creation-api/tables.md) for the table elements most often restyled after the fact.
* [Paragraphs and text](/core/create/document-creation-api/paragraphs-and-text.md) for the style properties available on runs and paragraphs.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.apryse.com/core/create/document-creation-api/traverse-the-content-tree.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
