xsql
Language

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 keywords

The 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> element

Use 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 gTAG tROOT
Matchesfirst element with tag/name/id == gevery element with tag == tevery element, any tag
Depththat one containerany depthany depth
Iteratesthe container's direct childrenthe matches themselvesthe matches themselves
Nested (IN ...)a subgroup found inside the current elementthe current element's subtree onlythe current element's subtree only

On this page