1. Go to this page and download the library: Download mougrim/yaml-cst library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
mougrim / yaml-cst example snippets
use Mougrim\YamlCst\DomainModel\YamlPatch;
use Mougrim\YamlCst\Factory\YamlLineMapFactory;
use Mougrim\YamlCst\Factory\YamlSyntaxExceptionFactory;
use Mougrim\YamlCst\Factory\YamlTreeSitterCoreFactory;
use Mougrim\YamlCst\Helper\YamlTextStyleHelper;
use Mougrim\YamlCst\YamlCstParser;
use Mougrim\YamlCst\YamlDocumentPatchApplier;
use Mougrim\YamlCst\YamlIndexBuilder;
use Mougrim\YamlCst\YamlPatchConflictChecker;
$lineMapFactory = new YamlLineMapFactory();
$core = (new YamlTreeSitterCoreFactory())->create(); // create once per process
$parser = new YamlCstParser(
$lineMapFactory,
new YamlIndexBuilder(new YamlTextStyleHelper()),
new YamlSyntaxExceptionFactory($lineMapFactory),
);
$applier = new YamlDocumentPatchApplier($parser, new YamlPatchConflictChecker());
$yaml = "database:\n host: localhost\n port: 5432\n";
$document = $parser->parse($yaml, $core);
// Read a value
echo $document->index->get(['database', 'host'])->valueText($yaml); // localhost
// Patch a value and get a new document
$span = $document->index->get(['database', 'host'])->valueSpan();
$updated = $applier->apply($document, $core, [new YamlPatch($span, 'production.db')]);
echo $updated->source; // database:\n host: production.db\n port: 5432\n
use Mougrim\YamlCst\Factory\YamlLineMapFactory;
use Mougrim\YamlCst\Factory\YamlSyntaxExceptionFactory;
use Mougrim\YamlCst\Factory\YamlTreeSitterCoreFactory;
use Mougrim\YamlCst\Helper\YamlTextStyleHelper;
use Mougrim\YamlCst\YamlCstParser;
use Mougrim\YamlCst\YamlDocumentPatchApplier;
use Mougrim\YamlCst\YamlIndexBuilder;
use Mougrim\YamlCst\YamlPatchConflictChecker;
// Create the native core once — reuse it for every parse() call.
$core = (new YamlTreeSitterCoreFactory())->create();
$lineMapFactory = new YamlLineMapFactory();
$parser = new YamlCstParser(
$lineMapFactory,
new YamlIndexBuilder(
textStyleHelper: new YamlTextStyleHelper(),
),
new YamlSyntaxExceptionFactory($lineMapFactory),
);
$conflictChecker = new YamlPatchConflictChecker();
$applier = new YamlDocumentPatchApplier($parser, $conflictChecker);
// Primary API — segment-based, unambiguous
$hostPair = $document->index->get(['database', 'host']);
echo $hostPair->keyText; // "host"
// Extract the value text using its byte span
$valueSpan = $hostPair->valueSpan();
echo substr($yaml, $valueSpan->startByte, $valueSpan->length());
// "localhost"
// Check whether a path exists before accessing it
if ($document->index->has(['database', 'port'])) {
$portPair = $document->index->get(['database', 'port']);
}
// Non-throwing lookup — returns null when not found
$portPair = $document->index->find(['database', 'port']);
if ($portPair !== null) {
// ...
}
// Get the raw value text directly (convenience method)
$hostText = $document->index->get(['database', 'host'])->valueText($yaml);
// "localhost"
// List direct children of a parent segment path
$dbChildren = $document->index->childrenOf(['database']);
foreach ($dbChildren as $pair) {
echo $pair->keyText . "\n";
// host, port, credentials
}
// Lookup a key whose name contains a literal dot — unambiguous with segments
$dotKeyPair = $document->index->find(['my.key']); // key literally named "my.key"
// All indexed segment paths in document order: [['database'], ['database','host'], ...]
$paths = $document->index->allPaths();
// Convenience: dot-joined path strings (fine when key names don't contain dots)
$dotPaths = $document->index->allDotPaths(); // ['database', 'database.host', ...]
$hostPair = $document->index->getByPath('database.host');
use Mougrim\YamlCst\DomainModel\YamlPatch;
$valueSpan = $document->index->get(['database', 'host'])->valueSpan();
// Collect patches and pass them to apply() — returns a new, re-parsed document
// $applier is created in the setup section above
$updated = $applier->apply($document, $core, [
new YamlPatch($valueSpan, 'production.db.example.com'),
]);
echo $updated->source;
// database:
// host: production.db.example.com
// port: 5432
// ...
use Mougrim\YamlCst\Enum\YamlNodeType;
use Mougrim\YamlCst\YamlCstSearcher;
$yaml = <<<YAML
servers:
- host: web1
port: 80
- host: web2
port: 80
YAML;
$document = $parser->parse($yaml, $core);
$searcher = new YamlCstSearcher();
// Find the first BLOCK_MAPPING_PAIR anywhere in the tree
$firstPair = $searcher->firstDescendantOfType(
$document->tree->root(),
YamlNodeType::BLOCK_MAPPING_PAIR,
);
// Iterate the direct BLOCK_MAPPING_PAIR children of a block-mapping node
$blockMapping = $searcher->firstDescendantOfType(
$document->tree->root(),
YamlNodeType::BLOCK_MAPPING,
);
if ($blockMapping !== null) {
foreach ($searcher->directMappingPairs($blockMapping) as $pair) {
$keyNode = $pair->childByField(\Mougrim\YamlCst\Enum\YamlNodeField::KEY);
echo $keyNode->text($yaml) . "\n"; // "servers"
}
}
// Iterate items in a block sequence using the convenience helper
$blockSequence = $searcher->firstDescendantOfType(
$document->tree->root(),
YamlNodeType::BLOCK_SEQUENCE,
);
if ($blockSequence !== null) {
foreach ($searcher->directSequenceItems($blockSequence) as $item) {
// $item is a block_sequence_item node
echo $item->type()?->value . "\n";
}
}
// Skip comment nodes during traversal
foreach ($node->namedChildren() as $child) {
if ($child->isExtra()) {
continue; // skip comments and other extras
}
// process $child
}
// Find ALL block-mapping pairs in the tree (not just the first)
$allPairs = $searcher->allDescendantsOfType(
$document->tree->root(),
YamlNodeType::BLOCK_MAPPING_PAIR,
);
// Navigate to a sibling node
$node = $searcher->firstDescendantOfType($document->tree->root(), YamlNodeType::BLOCK_MAPPING_PAIR);
if ($node !== null) {
$next = $node->nextNamedSibling();
if (!$next->isNull()) {
echo $next->type()?->value . "\n";
}
$prev = $node->previousNamedSibling();
if (!$prev->isNull()) {
echo $prev->type()?->value . "\n";
}
}
// Using valueText() — the shortest form
$host = $document->index->get(['database', 'host'])->valueText($yaml);
// Equivalent using spans
$span = $document->index->get(['database', 'host'])->valueSpan();
$host = $span !== null ? substr($yaml, $span->startByte, $span->length()) : null;
$helper = new YamlTextStyleHelper();
$rawValue = $document->index->get(['database', 'host'])->valueText($yaml); // '"localhost"'
// Minimal unescaping (only \" and '' are handled)
$value = $helper->normalizeScalar($rawValue); // 'localhost'
// Full YAML 1.2 unescaping (\n, \t, \\, \uXXXX, etc.)
$fullyUnescaped = $helper->fullyNormalizeScalar($rawValue); // 'localhost'
use Mougrim\YamlCst\Helper\YamlTextStyleHelper;
$helper = new YamlTextStyleHelper();
// Detect the end-of-line sequence used in the source ("\r\n" or "\n")
$eol = $helper->detectEndOfLine($yaml);
// Find the byte offset where the line containing $byteOffset starts
$lineStart = $helper->lineStart($yaml, $byteOffset);
// Extract the leading whitespace (indent) before a given byte offset
$indent = $helper->indentOfLineTo($yaml, $lineStart, $byteOffset);
// Find the byte offset after the next newline (useful for line-level patching)
$nextLine = $helper->nextLineBreakEnd($yaml, $byteOffset);
// Fully unescape a double-quoted YAML scalar (all YAML 1.2 escape sequences)
$resolved = $helper->fullyNormalizeScalar('"hello\\nworld"'); // "hello\nworld"
$core = (new YamlTreeSitterCoreFactory())->create(
coreLibPath: '/opt/lib/libtree-sitter.so',
yamlLibPath: '/opt/lib/libtree-sitter-yaml.so',
);