Group vs. Tag vs. Root
Three different ways to select elements, and when to use each.
Nearly every verb can target a group, a tag, or the document root. Picking the wrong one is the most common source of surprise, so here's the direct comparison.
GROUP
A group is the first element whose tag — or name/id attribute —
equals the given name.
SELECT GROUP goods; ; matches by tag OR name OR id, first match only
SELECT GROUP 110000; ; numeric name -> matches <Group id="110000">
SELECT GROUP "Group"; ; quoted -> for names colliding with keywordsThe verb then operates on (typically iterates) that one container's direct children.
TAG
A tag selector matches every element whose tag equals t, at any
depth in the document. Attributes don't participate in the match at all.
SELECT TAG ItemSpec; ; every ItemSpec, any depth
FOREACH i IN TAG ItemSpec SET i.reviewed = 1; ; document-wide edit
UPDATE TAG ItemSpec SET cost = 0 WHERE cost < 0;
DELETE TAG Obsolete; ; removes every <Obsolete> elementUse TAG for documents that have no reliable group/container structure —
where the elements you care about are scattered at different depths, not
gathered under one parent.
Nested TAG
Inside a loop, IN TAG t searches only the current element's subtree,
not the whole document:
FOREACH office IN offices
FOREACH m IN TAG Member
SET m.office = office.id
;A nested TAG search that matches nothing inside the current element
simply iterates zero times — it does not fall back to a document-wide
search.
ROOT
ROOT is TAG with the tag filter removed entirely: it matches every
element in the document, whatever its tag. Use it for a first exploratory
pass over a file whose structure you don't know yet — no need to guess a
tag name before you can look at the data:
SELECT ROOT OUTPUT id, type; ; every element, any tag
FOREACH v IN ROOT WHERE v.type = 0 OUTPUT v.id; ; filter once you see the shape
UPDATE ROOT SET reviewed = 1 WHERE cost > 500;Once you know the real tag (or group) name, prefer TAG/GROUP — they're
more precise and, for GROUP, cheaper to parallelize. Like TAG, IN ROOT
inside a nested loop only searches the current element's subtree.
Why it matters for parallelism
TAG and ROOT loops only take the parallel evaluate-then-apply path
after a disjointness check: since their matches can nest inside one another
(an ItemSpec inside an ItemSpec, or — for ROOT — any parent/child pair
at all), the interpreter verifies no match is nested inside another match
before parallelizing. GROUP loops don't need this check, since a group's
children are always a flat, non-overlapping set. See
Performance for the full picture.
Quick reference
GROUP g | TAG t | ROOT | |
|---|---|---|---|
| Matches | first element with tag/name/id == g | every element with tag == t | every element, any tag |
| Depth | that one container | any depth | any depth |
| Iterates | the container's direct children | the matches themselves | the matches themselves |
Nested (IN ...) | a subgroup found inside the current element | the current element's subtree only | the current element's subtree only |