Recursive AI

Dependency parsing in C#

OneNLP is a free, open-source natural language processing library for .NET from Recursive AI. MIT or Apache-2.0, no native dependencies.

Link words to their grammatical heads to find subjects and modifiers.

Terminal
dotnet add package RecursiveAI.OneNlp.Models.English

Requires .NET 10 (net10.0); .NET 9 and earlier aren’t supported.

C#
using RecursiveAI.OneNlp;
 
Doc doc = Nlp.Analyze(
    "The cat sleeps.", Language.English);
foreach (Token token in doc)
    Console.WriteLine(
        $"{token.Text}: {token.Dep}" +
        $" -> {token.Head.Text}");
Text
The: det -> cat
cat: nsubj -> sleeps
sleeps: root -> sleeps
.: punct -> sleeps

Unzip the example, then dotnet run.

Full program

The program analyzes “The cat sleeps.” and prints each token’s dependency label and head word. “cat” is the subject of “sleeps”; “The” modifies “cat”. The root token points to itself in the public token API.

The download’s Program.cs is the snippet above.

dotnet run prints:

Text
The: det -> cat
cat: nsubj -> sleeps
sleeps: root -> sleeps
.: punct -> sleeps

With only the core package, Analyze does not supply trained dependency annotations; reference the English model package for this example.

Variations

Extract noun phrases. Doc.NounChunks returns base noun phrases derived from the parse. This standalone snippet prints the phrase, not its individual tokens.

C#
using RecursiveAI.OneNlp;
 
Doc doc = Nlp.Analyze("The cat sleeps.", Language.English);
foreach (var phrase in doc.NounChunks)
    Console.WriteLine(phrase.Text);
Text
The cat

The short answer

For dependency parsing in C#, reference RecursiveAI.OneNlp.Models.English and analyze text with Nlp.Analyze(text, Language.English). Each token has a dependency relation in Dep, a head token in Head and its head’s document index in HeadIndex. The program above prints a small tree as readable token-to-head links.

The English model supplies the trained parser. The core library alone supplies segmentation but does not infer dependency relations. Keep the model package in your project even if your code only mentions core API types. The model package guide explains how models register with the API.

What is an example of dependency parsing in C#?

In “The cat sleeps.”, “sleeps” is the root, “cat” is its subject and “The” is a determiner attached to “cat”. Punctuation also has a dependency relation. The output includes every token so that you can inspect the entire result rather than just the subject you hoped to find.

Use token indices when storing edges. Words can repeat in a sentence, so the head’s text is useful for a walkthrough but is not a unique identifier. Retain the original document and the token indices together when building a graph or highlighting a relationship in a UI. The parser documentation describes how the model produces heads and relations.

The API’s root representation is also worth keeping separate from a file format’s conventions. In this example, the root token’s public Head is itself. An exporter may represent the root differently. Do not reinterpret every head value as a position in the original character string; token positions and character positions serve different purposes.

Is dependency parsing transition-based?

OneNLP’s documented parser is graph-based. It scores head relationships and decodes a maximum spanning tree, with one root per sentence. Its documentation explicitly says a transition-based design was not implemented. That is an architectural distinction, not a claim that one family is universally better.

Sentence boundaries matter because the parser builds a tree for each sentence. Existing boundaries are used; otherwise its boundary classifier supplies them. The documented parser splits sentences longer than 400 tokens into pieces of 400. If your application relies on a relation spanning an exceptionally long sentence, that behavior matters more than simply checking whether the call returned a document.

These are predictions from a trained model, not guaranteed facts about the text. Test the constructions your application cares about, especially fragments and domain-specific writing. A syntactically valid output tree is not the same thing as a correct interpretation.

What is the difference between constituency parsing and dependency parsing?

Dependency parsing returns word-to-head relationships. A constituency tree represents nested phrases instead; the dependency example here does not return such a tree. To get flat noun phrases from the dependency result, read Doc.NounChunks, as in the variation. It derives base noun phrases from parts of speech, heads and relations. “The cat” is returned as one phrase here. The phrase does not include the sentence’s verb or its final punctuation.

Noun chunks are flat phrases rather than a complete nested phrase tree. The documented rules choose phrase heads, extend across certain dependents and avoid overlapping phrases. Use them for a compact list of noun phrases; use individual dependency edges when you need the actual grammatical relationships. The noun chunk rules describe that distinction and the supported relation handling.

All onenlp recipes