Shape Constraint
Schema Definition
| Name | Type | Cardinality | Description |
|---|---|---|---|
| resource | https://schema.org/Text | 0..n | Optionally, the resource name this shape is applied to |
| selector | https://schema.org/Text | 0..n | Optionally, a CSS selector defining the constrained element |
| constraint | https://schema.org/Text | 1..n | A CSS selector defining the constraint |
Description
ShapeConstraint is an HTML microdata schema used by Pagelove to perform structural validation of document modifications using standard CSS selectors.
Rather than validating data using a separate schema language (such as SHACL or JSON Schema), Pagelove allows constraints to be expressed directly in HTML, using selectors that operate on the DOM being written.
A ShapeConstraint answers the question:
When something is modified, what structure must exist for that modification to be accepted?
What Shape Constraints do
When present in a Pagelove site, ShapeConstraint declarations participate in request processing for any HTTP method that mutates state (for example POST, PUT, or DELETE).
A constraint may apply to:
- The entire system
- One or more specific resources (via
resource) - One or more specific elements within those resources (via
selector)
If a constraint is violated, the modification is rejected.
Properties
resource (optional)
One or more resource names or path patterns the constraint applies to.
If omitted, the constraint applies globally.
Examples:
/users.html/admin/*
selector (optional)
One or more CSS selectors identifying the elements being constrained.
If omitted, the selector is treated as :root (the document as a whole)
The selector is matched against the element(s) targeted by the incoming modification.
constraint (required, repeatable)
Each constraint is a CSS selector that must match within the modified element’s subtree.
All listed constraints must succeed for the modification to be accepted.
Validation model (informal)
For each incoming mutating request:
- Identify all
ShapeConstraintdeclarations whoseresourcematches the request path (or which are global). - For each matching constraint:
- Check whether the request target element matches the constraint’s
selector(or:root). - If it does, evaluate every
constraintselector against the proposed modified DOM fragment.
- Check whether the request target element matches the constraint’s
- If any selector fails to match:
- Reject the request with HTTP 422 Unprocessable Content.
- Otherwise:
- Apply the modification normally.
HTTP error behaviour
If one or more constraints fail during request processing, the server MUST respond with:
422 Unprocessable Content
No partial modification is applied.
Example
The following constraint enforces that any modified list item representing a User must contain both username and email microdata properties.
<div itemscope itemtype="https://pagelove.org/ShapeConstraint">
<p>
When the selector <code itemprop="selector">li[itemtype*=User]</code>
matches, the following elements must be present:
</p>
<ul>
<li itemprop="constraint"><code>:has([itemprop="username"])</code></li>
<li itemprop="constraint"><code>:has([itemprop="email"])</code></li>
</ul>
</div>
Meaning
This declaration means:
For any POST or PUT that modifies an element matching li[itemtype*=User] The modified DOM fragment must contain:
- [itemprop="username"]
- [itemprop="email"]
If either is missing, the request is rejected with 422 Unprocessable Content.
For any DELETE, find the closest ancestor that matches li[itemtype*=User]. If there is one, then it must contain:
- [itemprop="username"]
- [itemprop="email"]
If either is missing, the request is rejected with 409 Conflict.