uCalc API Version: 2.1.3-preview.2 Released: 6/16/2026

Warning

uCalc API Preview Release Notice:The documentation describes the intended behavior of the API. The current preview build contains incomplete features, unoptimized performance, and is subject to breaking changes.

LocalTransformer = [Transformer]

Property

Product: 

Transformer Library

Class: 

Rule

Gets a nested Transformer instance scoped exclusively to the text matched by this rule, enabling hierarchical parsing.

Remarks

🎯 Nested Parsing with LocalTransformer

The LocalTransformer property provides access to a powerful nested parsing engine. It returns a new Transformer instance whose scope is limited exclusively to the text segment matched by the parent Rule. This allows you to "zoom in" on a match and perform a second, independent set of find or transform operations on just that content.

This creates a hierarchical or multi-pass parsing model, which is essential for structured data formats like HTML, XML, or nested configuration files.

⚙️ Key Behaviors

Scope Isolation

A local transformer operates in a sandbox. It sees only the text captured by its parent rule's pattern and is completely unaware of the surrounding document.

Settings Inheritance

For convenience, a local transformer automatically inherits the settings of its parent, including:

This means you don't have to reconfigure the entire parsing environment for each nested level. For example, if you set .StatementSensitive(false) on the parent, the local transformer will also treat newlines as whitespace.

Nested Match Results

Matches found by a local transformer are considered "child" matches. The Matches collection stores this hierarchy, allowing you to filter the results view using members of the MatchesOption enum:

  • MatchesOption::All: Shows all matches, both parent and child.
  • MatchesOption::RootLevelOnly: Shows only the top-level matches from the parent transformer.
  • MatchesOption::InnermostOnly: Shows only the final, most deeply nested matches.

To check if a rule is part of a local transformer, you can use the IsChildRule property.

💡 Why uCalc? (Comparative Analysis)

vs. Regular Expressions

Traditional regex has no built-in concept of hierarchical parsing. To achieve a similar result, you would need to:

  1. Write a regex to find and capture the outer content block.
  2. Extract the captured string into a new variable in your application code.
  3. Write and execute a second regex against that new string.
  4. Manually stitch the results together, keeping track of original offsets if needed.

This multi-step, imperative process is verbose and error-prone.

uCalc's LocalTransformer integrates this entire workflow into a single, declarative model. You define the parent-child relationship between rules, and the engine handles the substring extraction, nested searching, and result hierarchy automatically. This leads to code that is significantly cleaner, more robust, and easier to maintain.

Examples

A simple example showing how to extract a value from a nested configuration block.
				
					using uCalcSoftware;

var uc = new uCalc();
var t = uc.NewTransformer();
t.Text = "Config { setting = 123; }";

// 1. Define the parent rule to capture the content inside the braces.
var parentRule = t.Pattern("Config '{' {body} '}'").SetStatementSensitive(false);

// 2. Get the local transformer for the parent rule.
var local_t = parentRule.LocalTransformer;

// 3. Define a rule that operates ONLY on the text captured by '{body}'.
local_t.FromTo("setting = {val}", "Found Value: {val}");

// 4. Perform the transformation.
// The local rule will run on the text " setting = 123; ".
t.Transform();

Console.WriteLine(t.Text);
				
			
Config { Found Value: 123; }
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

int main() {
   uCalc uc;
   auto t = uc.NewTransformer();
   t.Text("Config { setting = 123; }");

   // 1. Define the parent rule to capture the content inside the braces.
   auto parentRule = t.Pattern("Config '{' {body} '}'").SetStatementSensitive(false);

   // 2. Get the local transformer for the parent rule.
   auto local_t = parentRule.LocalTransformer();

   // 3. Define a rule that operates ONLY on the text captured by '{body}'.
   local_t.FromTo("setting = {val}", "Found Value: {val}");

   // 4. Perform the transformation.
   // The local rule will run on the text " setting = 123; ".
   t.Transform();

   cout << t.Text() << endl;
}
				
			
Config { Found Value: 123; }
				
					Imports System
Imports uCalcSoftware
Public Module Program
   Public Sub Main()
      Dim uc As New uCalc()
      Dim t = uc.NewTransformer()
      t.Text = "Config { setting = 123; }"
      
      '// 1. Define the parent rule to capture the content inside the braces.
      Dim parentRule = t.Pattern("Config '{' {body} '}'").SetStatementSensitive(false)
      
      '// 2. Get the local transformer for the parent rule.
      Dim local_t = parentRule.LocalTransformer
      
      '// 3. Define a rule that operates ONLY on the text captured by '{body}'.
      local_t.FromTo("setting = {val}", "Found Value: {val}")
      
      '// 4. Perform the transformation.
      '// The local rule will run on the text " setting = 123; ".
      t.Transform()
      
      Console.WriteLine(t.Text)
   End Sub
End Module
				
			
Config { Found Value: 123; }
A practical example of parsing a specific HTML section and applying transformations only to the elements within it.
				
					using uCalcSoftware;

var uc = new uCalc();
// Note the change in section/div/h2
var t = uc.NewTransformer();

// The parent rule will find the <section> block and make its content available to a local transformer.
// StatementSensitive(false) is needed so the multiline content is captured.
var parentRule = t.Pattern("<section>{body}</section>");
parentRule.StatementSensitive = false;

// Get the local transformer for the <section> block.
var section_t = parentRule.LocalTransformer;

// These rules will ONLY run on the content inside the <section> tag.
section_t.FromTo("<h2>{text}</h2>", "<h1>====> {@Eval: UCase(text)} <====</h1>");
section_t.FromTo("<p>{text}</p>", "<p>SELECTED: {text}</p>");

var sourceHtml =
"""

<div>
  <h2>Article One</h2>
  <p>This is NOT in the section.</p>
</div>

<section>
  <div>
    <h2>Article Two</h2>
    <p>This one IS inside the section.</p>
  </div>
</section>

""";

t.Text = sourceHtml;
t.Transform();
Console.WriteLine(t.Text);
				
			
<div>
  <h2>Article One</h2>
  <p>This is NOT in the section.</p>
</div>

<section>
  <div>
    <h1>====> ARTICLE TWO <====</h1>
    <p>SELECTED: This one IS inside the section.</p>
  </div>
</section>
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

int main() {
   uCalc uc;
   // Note the change in section/div/h2
   auto t = uc.NewTransformer();

   // The parent rule will find the <section> block and make its content available to a local transformer.
   // StatementSensitive(false) is needed so the multiline content is captured.
   auto parentRule = t.Pattern("<section>{body}</section>");
   parentRule.StatementSensitive(false);

   // Get the local transformer for the <section> block.
   auto section_t = parentRule.LocalTransformer();

   // These rules will ONLY run on the content inside the <section> tag.
   section_t.FromTo("<h2>{text}</h2>", "<h1>====> {@Eval: UCase(text)} <====</h1>");
   section_t.FromTo("<p>{text}</p>", "<p>SELECTED: {text}</p>");

   auto sourceHtml =
   R"(
<div>
  <h2>Article One</h2>
  <p>This is NOT in the section.</p>
</div>

<section>
  <div>
    <h2>Article Two</h2>
    <p>This one IS inside the section.</p>
  </div>
</section>
)";

   t.Text(sourceHtml);
   t.Transform();
   cout << t.Text() << endl;
}
				
			
<div>
  <h2>Article One</h2>
  <p>This is NOT in the section.</p>
</div>

<section>
  <div>
    <h1>====> ARTICLE TWO <====</h1>
    <p>SELECTED: This one IS inside the section.</p>
  </div>
</section>
				
					Imports System
Imports uCalcSoftware
Public Module Program
   Public Sub Main()
      Dim uc As New uCalc()
      '// Note the change in section/div/h2
      Dim t = uc.NewTransformer()
      
      '// The parent rule will find the <section> block and make its content available to a local transformer.
      '// StatementSensitive(false) is needed so the multiline content is captured.
      Dim parentRule = t.Pattern("<section>{body}</section>")
      parentRule.StatementSensitive = false
      
      '// Get the local transformer for the <section> block.
      Dim section_t = parentRule.LocalTransformer
      
      '// These rules will ONLY run on the content inside the <section> tag.
      section_t.FromTo("<h2>{text}</h2>", "<h1>====> {@Eval: UCase(text)} <====</h1>")
      section_t.FromTo("<p>{text}</p>", "<p>SELECTED: {text}</p>")
      
      Dim sourceHtml =
      "
<div>
  <h2>Article One</h2>
  <p>This is NOT in the section.</p>
</div>

<section>
  <div>
    <h2>Article Two</h2>
    <p>This one IS inside the section.</p>
  </div>
</section>
"
      
      t.Text = sourceHtml
      t.Transform()
      Console.WriteLine(t.Text)
   End Sub
End Module
				
			
<div>
  <h2>Article One</h2>
  <p>This is NOT in the section.</p>
</div>

<section>
  <div>
    <h1>====> ARTICLE TWO <====</h1>
    <p>SELECTED: This one IS inside the section.</p>
  </div>
</section>
Internal Test: Verifies the filtering of nested matches using RootLevelOnly and InnermostOnly options.
				
					using uCalcSoftware;

var uc = new uCalc();
var t = uc.NewTransformer();
var txt = "<p id='aa'>xyz</p><p id='bb'>Hello</p ><p id='cc'>World</p>";
t.Text = txt;

// Parent rule matches the <p> tag. Its local transformer then extracts the 'id' attribute.
var parentRule = t.Pattern("<p {etc}>");
parentRule.LocalTransformer.FromTo("id={@string:id}", "{id}");
t.Filter();

Console.WriteLine("--- All Matches (Parent and Child) ---");
Console.WriteLine(t.GetMatches(MatchesOption.All).Text);
Console.WriteLine("");

Console.WriteLine("--- RootLevelOnly (Parent Matches) ---");
Console.WriteLine(t.GetMatches(MatchesOption.RootLevelOnly).Text);
Console.WriteLine("");

Console.WriteLine("--- InnermostOnly (Child Matches) ---");
Console.WriteLine(t.GetMatches(MatchesOption.InnermostOnly).Text);
				
			
--- All Matches (Parent and Child) ---
<p aa>
aa
<p bb>
bb
<p cc>
cc

--- RootLevelOnly (Parent Matches) ---
<p aa>
<p bb>
<p cc>

--- InnermostOnly (Child Matches) ---
aa
bb
cc
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

int main() {
   uCalc uc;
   auto t = uc.NewTransformer();
   auto txt = "<p id='aa'>xyz</p><p id='bb'>Hello</p ><p id='cc'>World</p>";
   t.Text(txt);

   // Parent rule matches the <p> tag. Its local transformer then extracts the 'id' attribute.
   auto parentRule = t.Pattern("<p {etc}>");
   parentRule.LocalTransformer().FromTo("id={@string:id}", "{id}");
   t.Filter();

   cout << "--- All Matches (Parent and Child) ---" << endl;
   cout << t.GetMatches(MatchesOption::All).Text() << endl;
   cout << "" << endl;

   cout << "--- RootLevelOnly (Parent Matches) ---" << endl;
   cout << t.GetMatches(MatchesOption::RootLevelOnly).Text() << endl;
   cout << "" << endl;

   cout << "--- InnermostOnly (Child Matches) ---" << endl;
   cout << t.GetMatches(MatchesOption::InnermostOnly).Text() << endl;
}
				
			
--- All Matches (Parent and Child) ---
<p aa>
aa
<p bb>
bb
<p cc>
cc

--- RootLevelOnly (Parent Matches) ---
<p aa>
<p bb>
<p cc>

--- InnermostOnly (Child Matches) ---
aa
bb
cc
				
					Imports System
Imports uCalcSoftware
Public Module Program
   Public Sub Main()
      Dim uc As New uCalc()
      Dim t = uc.NewTransformer()
      Dim txt = "<p id='aa'>xyz</p><p id='bb'>Hello</p ><p id='cc'>World</p>"
      t.Text = txt
      
      '// Parent rule matches the <p> tag. Its local transformer then extracts the 'id' attribute.
      Dim parentRule = t.Pattern("<p {etc}>")
      parentRule.LocalTransformer.FromTo("id={@string:id}", "{id}")
      t.Filter()
      
      Console.WriteLine("--- All Matches (Parent and Child) ---")
      Console.WriteLine(t.GetMatches(MatchesOption.All).Text)
      Console.WriteLine("")
      
      Console.WriteLine("--- RootLevelOnly (Parent Matches) ---")
      Console.WriteLine(t.GetMatches(MatchesOption.RootLevelOnly).Text)
      Console.WriteLine("")
      
      Console.WriteLine("--- InnermostOnly (Child Matches) ---")
      Console.WriteLine(t.GetMatches(MatchesOption.InnermostOnly).Text)
   End Sub
End Module
				
			
--- All Matches (Parent and Child) ---
<p aa>
aa
<p bb>
bb
<p cc>
cc

--- RootLevelOnly (Parent Matches) ---
<p aa>
<p bb>
<p cc>

--- InnermostOnly (Child Matches) ---
aa
bb
cc
LocalTransformer, HasLocalTransformer, IsChildRule
				
					using uCalcSoftware;

var uc = new uCalc();
// Note the change in section/div/h2
var t = uc.NewTransformer();

var rule = t.Pattern("<section>{body}</section>").SetStatementSensitive(false);
var section = rule.LocalTransformer;
section.FromTo("<h2>{text}</h2>", "<h1>====> {@Eval: UCase(text)} <====</h1>");
section.SkipOver("&{entity};");
var ch = section.FromTo("<p>{text}</p>", "<p>SELECTED: {text}</p>");

Console.WriteLine($"Has a local transformer: {rule.HasLocalTransformer}");
Console.WriteLine($"rule is a child rule: {rule.IsChildRule}");
Console.WriteLine($"ch is a child rule: {ch.IsChildRule}");

var HtmlText =
"""

<div class="article" data-id="1">
  <h2>Article One</h2>
  <p>This is the first article.</p>
</div>

<div class="article" data-id="2">
  <h2>Article Two</h2>
  <p>This is the second article.</p>
</div>

<section>
  <div class="article" data-id="3">
    <h2>Article Three</h2>
    <p>This one is inside a &lt;section&gt;.</p>
  </div>
</section>

<div class="article" data-id="4">
  <h2>Article Four</h2>
  <p>This is the fourth article.</p>
</div>

""";

t.Text = HtmlText;
t.Transform();
Console.WriteLine(t.Text);


				
			
Has a local transformer: True
rule is a child rule: False
ch is a child rule: True

<div class="article" data-id="1">
  <h2>Article One</h2>
  <p>This is the first article.</p>
</div>

<div class="article" data-id="2">
  <h2>Article Two</h2>
  <p>This is the second article.</p>
</div>

<section>
  <div class="article" data-id="3">
    <h1>====> ARTICLE THREE <====</h1>
    <p>SELECTED: This one is inside a &lt;section&gt;.</p>
  </div>
</section>

<div class="article" data-id="4">
  <h2>Article Four</h2>
  <p>This is the fourth article.</p>
</div>
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

#define tf(IsTrue) ((IsTrue) ? "True" : "False")

int main() {
   uCalc uc;
   // Note the change in section/div/h2
   auto t = uc.NewTransformer();

   auto rule = t.Pattern("<section>{body}</section>").SetStatementSensitive(false);
   auto section = rule.LocalTransformer();
   section.FromTo("<h2>{text}</h2>", "<h1>====> {@Eval: UCase(text)} <====</h1>");
   section.SkipOver("&{entity};");
   auto ch = section.FromTo("<p>{text}</p>", "<p>SELECTED: {text}</p>");

   cout << "Has a local transformer: " << tf(rule.HasLocalTransformer()) << endl;
   cout << "rule is a child rule: " << tf(rule.IsChildRule()) << endl;
   cout << "ch is a child rule: " << tf(ch.IsChildRule()) << endl;

   auto HtmlText =
   R"(
<div class="article" data-id="1">
  <h2>Article One</h2>
  <p>This is the first article.</p>
</div>

<div class="article" data-id="2">
  <h2>Article Two</h2>
  <p>This is the second article.</p>
</div>

<section>
  <div class="article" data-id="3">
    <h2>Article Three</h2>
    <p>This one is inside a &lt;section&gt;.</p>
  </div>
</section>

<div class="article" data-id="4">
  <h2>Article Four</h2>
  <p>This is the fourth article.</p>
</div>
)";

   t.Text(HtmlText);
   t.Transform();
   cout << t.Text() << endl;


}
				
			
Has a local transformer: True
rule is a child rule: False
ch is a child rule: True

<div class="article" data-id="1">
  <h2>Article One</h2>
  <p>This is the first article.</p>
</div>

<div class="article" data-id="2">
  <h2>Article Two</h2>
  <p>This is the second article.</p>
</div>

<section>
  <div class="article" data-id="3">
    <h1>====> ARTICLE THREE <====</h1>
    <p>SELECTED: This one is inside a &lt;section&gt;.</p>
  </div>
</section>

<div class="article" data-id="4">
  <h2>Article Four</h2>
  <p>This is the fourth article.</p>
</div>
				
					Imports System
Imports uCalcSoftware
Public Module Program
   Public Sub Main()
      Dim uc As New uCalc()
      '// Note the change in section/div/h2
      Dim t = uc.NewTransformer()
      
      Dim rule = t.Pattern("<section>{body}</section>").SetStatementSensitive(false)
      Dim section = rule.LocalTransformer
      section.FromTo("<h2>{text}</h2>", "<h1>====> {@Eval: UCase(text)} <====</h1>")
      section.SkipOver("&{entity};")
      Dim ch = section.FromTo("<p>{text}</p>", "<p>SELECTED: {text}</p>")
      
      Console.WriteLine($"Has a local transformer: {rule.HasLocalTransformer}")
      Console.WriteLine($"rule is a child rule: {rule.IsChildRule}")
      Console.WriteLine($"ch is a child rule: {ch.IsChildRule}")
      
      Dim HtmlText =
      "
<div class=""article"" data-id=""1"">
  <h2>Article One</h2>
  <p>This is the first article.</p>
</div>

<div class=""article"" data-id=""2"">
  <h2>Article Two</h2>
  <p>This is the second article.</p>
</div>

<section>
  <div class=""article"" data-id=""3"">
    <h2>Article Three</h2>
    <p>This one is inside a &lt;section&gt;.</p>
  </div>
</section>

<div class=""article"" data-id=""4"">
  <h2>Article Four</h2>
  <p>This is the fourth article.</p>
</div>
"
      
      t.Text = HtmlText
      t.Transform()
      Console.WriteLine(t.Text)
      
      
   End Sub
End Module
				
			
Has a local transformer: True
rule is a child rule: False
ch is a child rule: True

<div class="article" data-id="1">
  <h2>Article One</h2>
  <p>This is the first article.</p>
</div>

<div class="article" data-id="2">
  <h2>Article Two</h2>
  <p>This is the second article.</p>
</div>

<section>
  <div class="article" data-id="3">
    <h1>====> ARTICLE THREE <====</h1>
    <p>SELECTED: This one is inside a &lt;section&gt;.</p>
  </div>
</section>

<div class="article" data-id="4">
  <h2>Article Four</h2>
  <p>This is the fourth article.</p>
</div>
MatchesOption: RootLevelOnly and InnermostOnly
				
					using uCalcSoftware;

var uc = new uCalc();
var t = uc.NewTransformer();
var txt = "<p id='aa'>xyz</p><p id='bb'>Hello</p ><p id='cc'>World</p>";
t.Str(txt);

t.Pattern("<p {etc}>").LocalTransformer.FromTo("id={@string:id}", "{id}");
t.Filter();


Console.WriteLine("All matches");
Console.WriteLine("-----------");
Console.WriteLine(t.GetMatches(MatchesOption.All).Text); // All is the default
Console.WriteLine("");

Console.WriteLine("RootLevelOnly");
Console.WriteLine("-------------");
Console.WriteLine(t.GetMatches(MatchesOption.RootLevelOnly).Text);
Console.WriteLine("");

Console.WriteLine("InnermostOnly");
Console.WriteLine("-------------");
Console.WriteLine(t.GetMatches(MatchesOption.InnermostOnly).Text);
Console.WriteLine("");
				
			
All matches
-----------
<p aa>
aa
<p bb>
bb
<p cc>
cc

RootLevelOnly
-------------
<p aa>
<p bb>
<p cc>

InnermostOnly
-------------
aa
bb
cc
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

int main() {
   uCalc uc;
   auto t = uc.NewTransformer();
   auto txt = "<p id='aa'>xyz</p><p id='bb'>Hello</p ><p id='cc'>World</p>";
   t.Str(txt);

   t.Pattern("<p {etc}>").LocalTransformer().FromTo("id={@string:id}", "{id}");
   t.Filter();


   cout << "All matches" << endl;
   cout << "-----------" << endl;
   cout << t.GetMatches(MatchesOption::All).Text() << endl; // All is the default
   cout << "" << endl;

   cout << "RootLevelOnly" << endl;
   cout << "-------------" << endl;
   cout << t.GetMatches(MatchesOption::RootLevelOnly).Text() << endl;
   cout << "" << endl;

   cout << "InnermostOnly" << endl;
   cout << "-------------" << endl;
   cout << t.GetMatches(MatchesOption::InnermostOnly).Text() << endl;
   cout << "" << endl;
}
				
			
All matches
-----------
<p aa>
aa
<p bb>
bb
<p cc>
cc

RootLevelOnly
-------------
<p aa>
<p bb>
<p cc>

InnermostOnly
-------------
aa
bb
cc
				
					Imports System
Imports uCalcSoftware
Public Module Program
   Public Sub Main()
      Dim uc As New uCalc()
      Dim t = uc.NewTransformer()
      Dim txt = "<p id='aa'>xyz</p><p id='bb'>Hello</p ><p id='cc'>World</p>"
      t.Str(txt)
      
      t.Pattern("<p {etc}>").LocalTransformer.FromTo("id={@string:id}", "{id}")
      t.Filter()
      
      
      Console.WriteLine("All matches")
      Console.WriteLine("-----------")
      Console.WriteLine(t.GetMatches(MatchesOption.All).Text) '// All is the default
      Console.WriteLine("")
      
      Console.WriteLine("RootLevelOnly")
      Console.WriteLine("-------------")
      Console.WriteLine(t.GetMatches(MatchesOption.RootLevelOnly).Text)
      Console.WriteLine("")
      
      Console.WriteLine("InnermostOnly")
      Console.WriteLine("-------------")
      Console.WriteLine(t.GetMatches(MatchesOption.InnermostOnly).Text)
      Console.WriteLine("")
   End Sub
End Module
				
			
All matches
-----------
<p aa>
aa
<p bb>
bb
<p cc>
cc

RootLevelOnly
-------------
<p aa>
<p bb>
<p cc>

InnermostOnly
-------------
aa
bb
cc