> 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/bookmark/outline.md).

# Navigate PDF outline tree on Server/Desktop

Learn how to navigate, read, add, and edit PDF outlines and bookmarks with a full code sample. Understand the structure of an outline tree in a PDF document and create new bookmarks easily. The Apryse

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

Packages are required for production license. Trial keys have unlimited access to all features.

Demo showcases functionality using WebViewer UI.

<a href="https://apryse.com/capabilities#PageManipulation" class="button primary">Package: Page Manipulation</a><a href="https://showcase.apryse.com/create-thumbnail" class="button primary">Live demo</a>
{% endhint %}

The basic code needed to navigate an outline tree and print its result:

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

```csharp
void PrintIdent(Bookmark item)
{
  int ident = item.GetIdent() - 1;
  for (int i=0; i < ident; ++i) {
    Console.Write("  ");
  }
}
void PrintOutlineTree(Bookmark item)
{
  for (; item.IsValid(); item=item.GetNext()) {
    PrintIdent(item);
    Console.Write("{0:s}{1:s} ACTION -> ", (item.IsOpen() ? "- " : "+ "), item.GetTitle());
    if (item.HasChildren()) {
      PrintOutlineTree(item.GetFirstChild());
    }
  }
}
PDFDoc doc = new PDFDoc(filename);
Bookmark root = doc.GetFirstBookmark();
PrintOutlineTree(root);
```

{% endcode %}
{% endtab %}

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

```cpp
void PrintIndent(Bookmark item) 
{
	int ident = item.GetIndent() - 1;
	for (int i=0; i<ident; ++i) {
    cout << "  ";
  }
}
void PrintOutlineTree(Bookmark item)
{
	for (; item.IsValid(); item=item.GetNext()) {
		PrintIndent(item);
    cout << (item.IsOpen() ? "- " : "+ ") << item.GetTitle() << " ACTION -> ";
		if (item.HasChildren()) {
			PrintOutlineTree(item.GetFirstChild());
		}
	}
}
PDFDoc doc(filename);
Bookmark root = doc.GetFirstBookmark();
PrintOutlineTree(root);
```

{% endcode %}
{% endtab %}

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

```go
func PrintIndent(item Bookmark){
  indent := item.GetIndent() - 1
  i := 0
  for i < indent{
    os.Stdout.Write([]byte("  "))
    i = i + 1
  }
}
func PrintOutlineTree (item Bookmark){
  for item.IsValid(){
    PrintIndent(item)
    if item.IsOpen(){
      os.Stdout.Write([]byte("- " + item.GetTitle() + " ACTION -> "))
    }else{
      os.Stdout.Write([]byte("+ " + item.GetTitle() + " ACTION -> "))
    } 
    if item.HasChildren(){        
      PrintOutlineTree(item.GetFirstChild())
    }
    item = item.GetNext()
  }
}            
doc := NewPDFDoc(filename)
root := doc.GetFirstBookmark()
PrintOutlineTree(root)
```

{% endcode %}
{% endtab %}

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

```java
void PrintIndent(Bookmark item) throws PDFNetException {
  int ident = item.getIndent() - 1;
  for (int i = 0; i < ident; ++i) {
    System.out.print("  ");
  }
}
void PrintOutlineTree(Bookmark item) throws PDFNetException {
  for (; item.isValid(); item = item.getNext()) {
    PrintIndent(item);
    System.out.print((item.isOpen() ? "- " : "+ ") + item.getTitle() + " ACTION -> ");
    if (item.hasChildren()) {
      PrintOutlineTree(item.getFirstChild());
    }
  }
}
PDFDoc doc = new PDFDoc(filename);
Bookmark root = doc.getFirstBookmark();
PrintOutlineTree(root);
```

{% endcode %}
{% endtab %}

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

```js
async function main() {
  const printIndent = async(item, str) => {
    const ident = (await item.getIndent()) - 1;
    for (let i = 0; i < ident; ++i) {
      str += '  ';
    }
    return str;
  };
  const printOutlineTree = async(item) => {
    for (; item != null; item = await item.getNext()) {
      let IndentString = await printIndent(item, IndentString);
      let TitleString = await item.getTitle();
      console.log(IndentString + (await item.isOpen()) ? '- ' : '+ ') + TitleString + ' Action -> ');
      if (await item.hasChildren()) {
        await printOutlineTree(await item.getFirstChild());
      }
    }
  };
  const doc = await PDFNet.PDFDoc.createFromURL(filename);
  const root = await docOut.getFirstBookmark();
  await printOutlineTree(root);
}
PDFNet.runWithCleanup(main);
```

{% endcode %}
{% endtab %}

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

```kotlin
@Throws(PDFNetException::class)
fun PrintIndent(item: Bookmark) {
  val ident = item.indent - 1
  for (i in 0 until ident) {
    print("  ")
  }
}
@Throws(PDFNetException::class)
fun PrintOutlineTree(item: Bookmark) {
  var item = item
  while (item.isValid) {
    PrintIndent(item)
    print((if (item.isOpen) "- " else "+ ") + item.title + " ACTION -> ")
    if (item.hasChildren()) {
      PrintOutlineTree(item.firstChild)
    }
    item = item.next
  }
}
val doc = PDFDoc(filename)
val root = doc.firstBookmark
PrintOutlineTree(root)
```

{% endcode %}
{% endtab %}

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

```objc
void PrintIndent(PTBookmark *item) 
{
	int ident = [item GetIndent] - 1;
	for (int i=0; i<ident; ++i) {
    printf("  ");
  }
}
void PrintOutlineTree(PTBookmark *item)
{
	for (; [item IsValid]; item=[item GetNext]) {
		PrintIndent(item);
		if ([item IsOpen]) {
			printf("- %s ACTION -> ", [[item GetTitle] UTF8String]);
		}
		else {
			printf("+ %s ACTION -> ", [[item GetTitle] UTF8String]);
		}
		if ([item HasChildren]) {
			PrintOutlineTree([item GetFirstChild]);
		}
	}
}
PTPDFDoc *doc = [[PTPDFDoc alloc] initWithFilepath: filename];
PTBookmark *root = [doc GetFirstBookmark];
PrintOutlineTree(root);
```

{% endcode %}
{% endtab %}

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

```swift
func PrintIndent(item: PTBookmark) -> String {
  let indent = item.getIndent() - 1
  var i = 0
  var str = ""
  while i < indent {
    str = str + ("  ")
    i += 1
  }
  return str
}
func PrintOutlineTree(item: PTBookmark) {
  var currentItem = item
  while currentItem.isValid() {
    let indent: String = PrintIndent(item: currentItem)
    if currentItem.isOpen() {
      print("\(indent)- \(currentItem.getTitle()!) ACTION -> ")
    }
    else {
      print("\(indent)+ \(currentItem.getTitle()!) ACTION -> ")
    }
    if currentItem.hasChildren() {
      PrintOutlineTree(item: currentItem.getFirstChild())
    }
    currentItem = currentItem.getNext()
  }
}
let doc: PTPDFDoc = PTPDFDoc(filepath: filename)
let root: PTBookmark = doc.getFirstBookmark()
PrintOutlineTree(item: root)
```

{% endcode %}
{% endtab %}

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

```php
function PrintIndent ($item) {
	$ident = $item->GetIndent() - 1;
	for ($i=0; $i<$ident; ++$i) {
		echo "     ";
	}
}
function PrintOutlineTree($item) {
	for (; $item->IsValid(); $item=$item->GetNext()) {
		PrintIndent($item);
		echo ($item->IsOpen() ? "- " : "+ ").$item->GetTitle()." ACTION -> ";
		if ($item->HasChildren()) {
			PrintOutlineTree($item->GetFirstChild());
		}
	}
}
$doc = new PDFDoc($filename);
$root = $doc->GetFirstBookmark();
PrintOutlineTree($root);
```

{% endcode %}
{% endtab %}

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

```python
def PrintIndent(item):
  indent = item.GetIndent() - 1
  i = 0
  while i < indent:
    sys.stdout.write("  ")
    i = i + 1
def PrintOutlineTree (item):
  while item.IsValid():
    PrintIndent(item)
    if item.IsOpen():
      sys.stdout.write("- " + item.GetTitle() + " ACTION -> ")
    else:
      sys.stdout.write("+ " + item.GetTitle() + " ACTION -> ")  
    if item.HasChildren():        
      PrintOutlineTree(item.GetFirstChild())
    item = item.GetNext()
doc = PDFDoc(filename)
root = doc.GetFirstBookmark()
PrintOutlineTree(root)
```

{% endcode %}
{% endtab %}

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

```ruby
def PrintIndent(item)
	indent = item.GetIndent() - 1
	i = 0
	while i < indent do
		print "  "
		i = i + 1
	end
end
def PrintOutlineTree (item)
	while item.IsValid() do
		PrintIndent(item)
		if item.IsOpen()
			print( "- " + item.GetTitle() + " ACTION -> ")
		else
			print("+ " + item.GetTitle() + " ACTION -> ")
		end  
		if item.HasChildren() 
			PrintOutlineTree(item.GetFirstChild())
		end
		item = item.GetNext()
	end
end
doc = PDFDoc.new(filename)
root = doc.GetFirstBookmark()
PrintOutlineTree(root)
```

{% endcode %}
{% endtab %}

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

```vb
Sub PrintIndent(ByVal item As Bookmark)
  Dim indent As Integer = item.GetIndent() - 1
  Dim i As Integer
  For i = 1 To indent
    Console.Write("  ")
  Next
End Sub
Public Shared Sub PrintOutlineTree(ByVal item As Bookmark)
  Do While item.IsValid()
    PrintIndent(item)
    If item.IsOpen Then
      Console.Write("- {0:s} ACTION -> ", item.GetTitle())
    Else
      Console.Write("+ {0:s} ACTION -> ", item.GetTitle())
    End If
    If item.HasChildren() Then   ' Recursively print children sub-trees
        PrintOutlineTree(item.GetFirstChild())
    End If
    item = item.GetNext()
  Loop
End Sub
Dim doc As PDFDoc = New PDFDoc(filename)
Dim root As Bookmark = doc1.GetFirstBookmark()
PrintOutlineTree(root)
```

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

[Read, add, edit PDF outlines and bookmarks - Full Sample](/core/get-started/samples/bookmarktest.md) Full code sample which illustrates how to read and edit existing outline items and create new bookmarks using the high-level API. Samples available in Python, C# (.Net), C++, Go, Java, Node.js (JavaScript), PHP, Ruby, VB. To use this code, you'll need to [download and get started with Server SDK](/core/get-started/get-started.md).

## About outline tree

A PDF document may display a document outline on the screen, allowing the user to navigate interactively from one part of the document to another. The outline consists of a tree-structured hierarchy of Bookmarks (sometimes called outline items), which serve as a "visual table of contents" to display the document's structure to the user.

Each Bookmark has a title that appears on screen, and an Action that specifies what happens when a user clicks on the Bookmark. The typical Action for a user-created Bookmark is to move to another location in the current document — although any Action can be specified.


---

# 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/bookmark/outline.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.
