L5Sharp 6.0.0

dotnet add package L5Sharp --version 6.0.0
                    
NuGet\Install-Package L5Sharp -Version 6.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="L5Sharp" Version="6.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="L5Sharp" Version="6.0.0" />
                    
Directory.Packages.props
<PackageReference Include="L5Sharp" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add L5Sharp --version 6.0.0
                    
#r "nuget: L5Sharp, 6.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package L5Sharp@6.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=L5Sharp&version=6.0.0
                    
Install as a Cake Addin
#tool nuget:?package=L5Sharp&version=6.0.0
                    
Install as a Cake Tool

L5Sharp.Core

A robust .NET library for programmatically interacting with Rockwell Automation's L5X import/export files.

Overview

L5Sharp.Core is the foundation of the L5Sharp ecosystem. It provides a strongly typed, intuitive, and performant API for reading, querying, modifying, and generating Logix L5X content. Whether you're automating project configuration, performing deep static analysis, or generating code, L5Sharp.Core offers the tools to handle Logix components and data structures with ease.

Key Features

  • High-Performance L5X Parsing: Load and parse large L5X files efficiently using L5X.Load or L5X.Parse.
  • Strongly Typed Component Model: Work with native C# representations of Logix components like Tag, Program, Routine, DataType, AddOnInstruction, Module, and more.
  • Advanced Querying with LINQ: Use the Query<T>() API to perform complex searches across your entire project.
  • Intuitive Tag Data System: Navigate and manipulate complex nested tag structures using the LogixData type system, which handles member alignment and data types automatically.
  • Fast Lookup Indexing: Enable project-wide indexing for O(1) lookups of components by name or path.
  • Comprehensive Modification Support: Add, remove, update, or replace any component within the L5X structure.
  • Source Code Analysis: Parse and analyze Logix RLL (Relay Ladder Logic) and Structured Text code.
  • Extensible Architecture: Add support for custom serializers or extend existing component models.

Installation

Install L5Sharp.Core via NuGet:

dotnet add package L5Sharp.Core

Quick Start

L5Sharp is centered around loading, querying, and updating L5X content. The primary entry points is the L5X class. The following example demonstrates how easy it is to dynamically find all tags of a specific type in the project and update a member value in a strongly typed way.

var project = L5X.Load("MyController.L5X");

var timers = project.Query<Tag>()
    .Where(t => t.DataType == "TIMER" && t.Dimensions == Dimensions.Empty)
    .Select(t => t.Value.As<TIMER>())
    .Where(t => t.PRE < 1000);

timers.ToList().ForEach(t => t.PRE = 5000);

project.Save("MyController.L5X");

Basic Usage

The following sections will walk through the library in more detail to highlight the primary features L5Sharp offers.

Loading & Creating an L5X

There are several factory methods for loading or creating an L5X instance. These factory methods mostly mimic underlying XElement factory methods.

// Use async overload for loading.
var project = await L5X.LoadAsync("MyProject.L5X", CancellationToken.None);

// Parse L5X string in memory.
var project = L5X.Parse("<RSLogix5000Content ... />");

// Create new L5X in memory. This will seed the project with the specified processor.
var project = L5X.New("MyProjectName", "1756-L84E", 36.1);

// Create an empty L5X in memory.
var project = L5X.Empty();

Accessing Components

The L5X class provides high-level collections for every major component found in the Studio 5k. Rockwell PLC developers should be familiar with these types and what they contain.

// Access globally scoped components.
var controllerTags = project.Tags;
var userDefinedTypes = project.DataTypes;
var aois = project.AddOnInstructions;
var modules = project.Modules;
var programs = project.Programs;
var tasks = project.Tasks;

// Access locally scoped components
var programTags = content.Programs.First().Tags;
var routines = content.Programs.First().Routines;

These collections return a LogixContainer<T> where T is the type of the compoent. This is a custom collection class that implement .NET collection interfaces like IList<T> and ICollection. All methods essentially query or update the underlying XML sequence. The API should be very straightforarad, but there are a few extension methods for the component types above that are worth calling out.

// Get a component in the collection with the specified name.
var tag = project.Tags.Get("MyTagname");

// Try to get component in the collection and return the instance if found.
var result = project.Tags.TryGet("MyTagName", out var tag);

// Remove a component by name.
var removed = project.Tags.Remove("MyTagName");

Query API

Instead of using the component collection above, L5X offers a simple and more flexible method for querying the content of the project file. Using the Query method allows you to find all elements of a specific type in the file.

// Tag query examples
var allTags = project.Query<Tag>();
var allTimerTags = project.Query<Tag>(t => t.DataType == "TIMER");
var tagsInProgram = project.Query<Tag>(t => t.Scope.Container == "SomeProgram");
var ioTags = project.Query<Tag>(t => t.TagName.Base.Contains(":"));

// Rung query examples
var allRungs = project.Query<Rung>();
var rungsWithInstruction = project.Query<Rung>(r => r.Text.Contains("ALARM"));

This query API searches across all scopes, making it much easier to find every tag in the project that meets specific filter criteria. Combined with strongly typed element classes and LINQ, this provides powerful capabilities for querying L5X files.

Fast Lookups

Another primary feature of L5Sharp.Core is the ability to perform fast lookups of components or entities within the L5X. This feature is exposed through a set of Get and TryGet methods on the L5X class.

// Gets a component by name.
var component = project.Get<DataType>("MyCustomType");

// Try to get a component by name and output the result if found.
var result = project.TryGet<Module>("LocalModuleName", out var component);

// This API supports controller scoped, program scoped, and nested tag member.
var tag = project.Get<Tag>("Program:SomeProgram.MyTagName.Member[2].Value");

// This API supports getting "code" type elements as well.
var result = project.TryGet<Rung>(12, "SomeProgram", "MainRoutine", out var rung);

These all operate in O(1) time. When the first call to one of these methods is made, the L5X is indexed and all LogixEntity types are stored in dictionaries. The internal index subscribes to element changes in the root L5X element, so that if any changes are made to the project, the index is invalidated and will reindex upon the next call.

The indexing code is designed to be as performant as possible, but use caution when calling these functions while also making changes in a tight loop, for this will cause reindexing each time. This API is mostly meant for fast read-only access to the document.

Entity Reference

All elements that are indexed get stored by a "reference" value. A Reference is a class that contains the route or path to a specific element in the L5X. This class is designed to resemble a URI type identifer for each element. All elements that impelement ILogixEntity will have a Reference property which is determined by its place in the XML hierarchy.

// Create a new in memory program tag.
var component = Tag.New<DINT>("Program:SomeProgram.MyTagName");

// Get the Reference property.
var reference = component.Reference;

// Write the results of the reference
Console.WriteLine(reference.Path); // Output: tag://SomeProgram/MyTagName
Console.WriteLine(reference.Type); // Output: tag
Console.WriteLine(reference.Container); // Output: SomeProgram
Console.WriteLine(reference.Id); // Output: MyTagName

References have the following format:

[Type]://[Container/][Routine/]Id[#Fragment]

  • Type: The reference type. This specifies what we are referencing (e.g., tag, datatype, rung, etc.).
  • Container: The container name (Program/AOI). This is optional and used for scoped elements (tag, routine, rung).
  • Routine: The routine name. This is optional and only used for code elements (rung, line, sheet).
  • Id: The identifer value (name/number). This specifies which type in the current scope is referenced.
  • Fragment: Optional metadata that refers to a subproperty or attribute of the target reference. This is mostly used to capture specific instruction text within rung references.

The Reference class offer several methods for building a reference value.

// Create reference to tag with provided name and scope.
var reference = Reference.To<Tag>("MyTag", Scope.Program("MyProgram")); // tag://MyProgram/MyTag

// Create reference to rung with instruction fragment "XIC(LocalTag)"
var reference = Reference.To("rung://MyProgram/MyRoutine/1#XIC(LocalTag)");

// Reference also has implicit string conversion.
Reference reference = "program://MyProgramName"

Since the reference value is used as the key for the internal indexing code, we can also use it to perform lookups in the L5X.

var component = project.Get("tag://MyProgram/MyTagName.SomeMember.Array[9].Element.12");

// Since you know this is a tag, you can cast it as needed. As<T>() is a build in cast method available on all types.
var tag = component.As<Tag>();

Creating Components

All components of L5Sharp.Core are designed to be very POCO like on the surface. For the most part, you can create a new component with the default constructor and initialize properties as needed.

var tag = new Tag { Name = "MyTag", Value = 123};
var dataType = new DataType { Name = "MyCustomType", Description = "This is a custom type." };
var task = new Task { Name = "PeriodicTask", Type = TaskType.Periodic, Rate = 100 };

Most components will have constructors that help with initialization.

var tag = new Tag("MyTag", 123);
var dataType = new DataType("MyCustomType");
var task = new Task("PeriodicTask", TaskType.Periodic)

And some types will have factory methods that help even further. Tag contains a fluent builder API that makes creating and configuring tag values much easier.

var tag = Tag.Create("SomeTimer")
    .WithValue<TIMER>(t => 
    {
        t.PRE = 5000;
        t.DN = true;
    })
    .WithDescription("This is a fluent builder...")
    .ReadOnly()
    .Build();

When a component or element is created in memory, it is not attached to an L5X until you add it to an appropriate container collection (Tags, DataType, Modules, etc.). This is important to remember because some navigation properties will return null if the object is not part of the XML hierarchy.

Modifying Components

L5Sharp offers various ways to configure or update components. At the simpliest level, you can directly set properties of a component as needed.

var tag = new Tag();

tag.Value = 50;
tag.Description = "Updated tag description";
tag.ExternalAccess = Access.ReadOnly;
tag.Usage = TasUsage.Public;
tag.AliasFor = "OtherTag.Member"

L5Sharp.Core is not strict in terms of property validation. In most cases, you can set a property on a component to any given value (acceptable by the value type) and attempt to import it into Studio. Studio will validate certain properties but be relaxed on others. For this reason, it's hard to fully perform validation ahead of time without manually importing permutations of content to see how Studio handles it. When we do find things Studio is strict on, we attempt to mimic that in the object construction and hide the details, such that the API can remain clean and simple.

All components contain methods for cloning or duplicating the instance with updated values. This is a key part of the library since in many cases, you want to copy existing templates and update only a few properties.

// Create a direct clone of the current object with no changes.
var clone = tag.Clone();

// Create a duplicate with updated config. This method will also add the duplicate to the L5X.
var duplicate = program.Duplicate(p => 
{
    p.Name = "Program_02";
    p.Description = "This is a different instance";
    p.Replace("Tag_01", "Tag_02"); //This method will perform find/replace of text in the new object.
});

Components also support "self-referencing" collection methods like AddAfter, AddBefore, Remove, and Replace. These functions operate relative to the current instance and require the element to be attached to a parent container or L5X. These methods mostly make use of the underlying XElement methods which do the same thing.

// Add a new object after current instance in the document.
rung.AddAfter(new Rung("XIC(SomeTag.12)OTE(AnotherTag)"));

// Replace current instance with new one.
tag.Replace(new Tag { Name = "UpdatedTag", Value = 123, Description = "Completely new instance"});

// Removes this instance from the L5X or parent container.
routine.Remove()

All LogixContainer<T> collection also support adding, removing, and updating elements as you would expect.

// Add a new component to a container
project.Tags.Add(new Tag { Name = "MyTag", Value = 100 });

// Remove a component from a container
project.Tags.Remove("OldTag");

// Bulk update components
project.Tags.Update(
    t => t.DataType == "TIMER", //update condition
    t => t.Description = "Updated TIMER description" //update action
);

Remember that all changes are directly applied to the underlying XML content. Once changes are complete, you can save the L5X to your desired output.

project.Save("Updated.L5X");

Tag Data

Controller Instance

The L5X class also contains access to the top level Controller object. This object contains all the high level controller or project-wide settings that are configurable in Studio. The controller will also contain the same reference to the component collections mentioned above.

var controller = porject.Controller;

var name = controller.Name;
var processor = controller.ProcessorType;
var revision = controller.Revision;
var commPath = controller.CommPath;
var tags = controller.Tags;
// etc.

When an L5X is loaded into memory, this library will "normalize" the XML structure by inserting a root Controller element and all nested component collection elements (if not already present). This ensures that we can access these collection properties without running into exceptions.

Partial Export Files

Not all L5X projects are complete project files. Some can be partial import/export files that target specific components (Module, DataType, etc.). To inspect the "context" of a given L5X file, access the Content property of the root L5X.

// Tells you whether this is a partial export or a complete project export.
var isPartial = project.Content.ContainsContext;

// The name and type of the target component in the export file.
var targetName = file.Content.TargetName;
var targetType = file.Content.TargetType;

Importing Content

Components

L5Sharp.Core provides strongly typed representations of all major Logix component types found in L5X files. Each component type offers intuitive properties and methods for inspection and modification, allowing you to work with Logix project elements as native C# objects. The following sections will outline some of the key components and common usage patterns.

Working with Tags

Architecture

L5Sharp.Core can be viewed in simple terms as a wrapper around LINQ to XML and the Rockwell XML schema for the L5X import/export files. Internally, all classes wrap an XElement and represent some segment of XML. The members of these classes are not much more than get/set accessors on the underlying elements and attributes that make up the XML segment. This means L5Sharp.Core is stateful and lazy in that deserialization is defered until the user calls a specific property or method. Deserializing a LogixElement is not much more than calling the constructor that initializes the underlying XML elememnt.

This library has several key abstractions that may be useful to understand. Ultimately, they are just means of code organization, and most users of this library will not interact with the base classes, but knowing the type hierarchy can help solidify the mental model of the library before using it.

LogixElement

The LogixElement class and corresponding ILogixElement interface are the core types of the library. They contain the internal XElement object that all derived types can interact with. This class contains all the protected getter and setter logic that makes the XML interaction in derived type much simpler. This type also exposes the Serialize() method that will return the underlying XElement. Users can leverage this to write custom extensions that interact with the internal XML structure. "Serialization" in this library is just a matter of returning the underlying data store and is not actively transforming to a different format.

LogixObject

The LogixObject<TObject> class derived directly from LogixElement and adds self-referential mutation methods such as adding, removing, replacing, and duplicating other objects of the same type in the L5X. These methods basically leverage the power of the underlying XElement and expose similar functions to help users mutate the object collections. This class takes the generic type of the implementing class to make it type safe.

LogixEntity

A LogixEntity<TEntity> (implementing ILogixEntity) is a type of element in the L5X that can be identified by some unique identifier (name, number, etc.). This type class adds a couple key properties, Reference and Scope. These properties identify where in the L5X document they exist. This is the primary type of the internal indexing code that is discussed later.

LogixComponent

The LogixComponent<TComponent> class implements ILogixComponent and adds property common to the main top level component classes in the library. Component class include Tag, DataType, Program, etc. All components can be identified by a name property. This class also adds functions for finding references, exporting the instance to a new L5X

LogixCode

Feedback & Support

We welcome your feedback! Please report bugs or request features via our GitHub Issues page.

License

L5Sharp.Core is licensed under the MIT License.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

    • No dependencies.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on L5Sharp:

Package Downloads
L5Sharp.Gateway

A gateway library for reading and writing Allen-Bradley Logix controller data using L5Sharp and libplctag

L5Sharp.Catalog

.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
6.0.0 109 3/20/2026
6.0.0-beta.11 80 3/5/2026
6.0.0-beta.10 93 2/18/2026
6.0.0-beta.9 48 2/18/2026
6.0.0-beta.8 136 2/18/2026
6.0.0-beta.7 81 1/19/2026
6.0.0-beta.6 58 12/31/2025
6.0.0-beta.5 125 12/21/2025
6.0.0-beta.4 167 12/19/2025
6.0.0-beta.3 167 12/19/2025
6.0.0-beta.2 75 12/12/2025
6.0.0-beta.1 122 12/5/2025
5.3.0 1,252 5/23/2025
5.2.0 170 5/23/2025
5.1.0 252 5/5/2025
5.0.0 234 5/4/2025
4.8.3 366 4/1/2025
4.8.2 248 3/31/2025
4.8.1 222 3/28/2025
4.8.0 268 2/15/2025
Loading failed