xml_path_equals
Query a structured document with a JSONPath expression and assert every match deep-equals the supplied value.
Semantics:
- Multiple matches — every match must equal the expected value.
- Zero matches — counts as a violation (the key the rule is enforcing doesn't exist).
- Unparseable files — one violation per file (not silently skipped).
- Numbers compare by value, in every format and at any depth:
equals: 1matches a document's1.0(or1e0), andequals: 1.0matches1. The comparison is exact: an integer equals a float only when the float is a whole number of exactly that value, so9007199254740993does not equal9007199254740992.0even though both round to the same 64-bit float. There is no other coercion: a string"1"never equals the number1. (New in v0.18; this supersedes the HCL whole-number caveat above.)
XML mapping applies to every XML surface: xml_path_*, json_schema_passes format: xml, and the xml: extract used by cross_file / file_graph / registry_paths_resolve. XML is mapped to the queryable tree with the xmltodict-style convention so the JSONPath reads like the XML — the document is { <root-element>: … } ($.Project…, $.project…); attributes are @name keys (['@Version'], in bracket notation, since .@Version is not valid JSONPath); a leaf element collapses to its text (<TargetFramework>net8.0</TargetFramework> → "net8.0"); namespaces flatten to the local name (Maven's default pom.xml namespace just works). Two properties of XML's data model to keep in mind:
- Every XML leaf value is a string. Quote expected values (
equals: "4.0.0", notequals: 4.0.0), reach for*_path_matches, and in ajson_schema_passesschema type XML fields asstringwith apattern—type: integer/boolean/numberalways fail against XML (every leaf is a string);type: array/objectadditionally depend on cardinality (next point). - Cardinality is data-dependent. A single
<dependency>is an object (a string for a leaf element); two or more become an array. A[*]wildcard therefore does not normalize cardinality —dependency[*]reads nothing for one element but every element for many, and a leaf query flips the same way (an attribute such as MSBuild'sCondition=also turns a would-be leaf string into a{ "@Condition": …, "#text": … }object). When a rule must handle both one and many, use recursive descent:$.Project.ItemGroup.ProjectReference..['@Include']reads the@Includeof one or many. Scope the..under a parent element so it does not over-match a same-named key elsewhere.
Full rationale and edge cases: docs/design/v0.10/xml_path.md.
Options
Section titled "Options"| Option | Type | Required | Default | Description |
|---|---|---|---|---|
equals | any value | yes | Expected value. Any JSON type (string, number, boolean, null, array, object). | |
if_present | boolean | false | When true, a query returning zero matches is silently OK - only real matches that fail the op produce violations. | |
path | string | yes | JSONPath expression rooted at $. Supports dot-access ($.foo.bar), array index ($.deps[0]), wildcards ($.deps[*]), filters, and every other RFC 9535 construct. |
Plus the common paths, level, id, when, and expect_matches fields. This table is generated from the JSON Schema; option types and defaults are authoritative.
Example
Section titled "Example"A project file targeting the wrong .NET framework
Section titled "A project file targeting the wrong .NET framework"The rule fires on this repository:
- src/
- src/Bad/
- src/Bad/Bad.csproj
✗ error csproj-net8
value at path does not equal expected: expected "net8.0", got "net6.0"
- src/Ok/
- src/Ok/Ok.csproj✓
<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><TargetFramework>net6.0</TargetFramework></PropertyGroup></Project><Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><TargetFramework>net8.0</TargetFramework></PropertyGroup></Project>With this .alint.yml:
version: 1rules: - id: csproj-net8 kind: xml_path_equals paths: "src/*/*.csproj" path: "$.Project.PropertyGroup.TargetFramework" equals: "net8.0" level: erroralint check reports:
--- src/Bad/Bad.csproj --------------------------------------------------------- x error csproj-net8 value at path does not equal expected: expected "net8.0", got "net6.0"
Summary (1 violation): x 1 error 0 passing * 1 failingEvery project file targets net8.0
Section titled "Every project file targets net8.0"This repository is compliant:
- src/
- src/App/
- src/App/App.csproj✓
<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><TargetFramework>net8.0</TargetFramework><Nullable>enable</Nullable></PropertyGroup></Project>With this .alint.yml:
version: 1rules: - id: csproj-net8 kind: xml_path_equals paths: "src/*/*.csproj" path: "$.Project.PropertyGroup.TargetFramework" equals: "net8.0" level: erroralint check reports:
v All 1 rule(s) passed.