@Override public void verify() throws TransformException { ItemList targets = mod.nearest(NodeTarget.class).targets(); List<Node> references = mod.references(); ItemList records = mod.supplementQuery().all("sort-proxy"); assert targets.size() == references.size(); assert records.size() == references.size(); for (int i = 0; i < targets.size(); i++) { Node target = targets.get(i).node(); Node restoredProxy = references.get(i); ItemList items = query.runOn(mod.scope(target.query())); if (items.size() != 1) throw new TransformException( "sort by corresponding node must select one node per target, but instead selected " + items.size() + ": " + items); Node proxy = items.get(0).node(); if (!restoredProxy.equals(proxy)) throw new TransformException("computed proxy changed"); if (!proxy .query() .single( "(count(preceding::*) + count(ancestor::*)) eq xs:integer($_1/@position)", records.get(i)) .booleanValue()) throw new SortingException("computed proxy moved"); } }
@Override public void restore() throws TransformException { ItemList runLengths = mod.supplementQuery().all("sort-siblings/@run-length"); ItemList targets = mod.nearest(NodeTarget.class).targets(); assert runLengths.size() == targets.size(); for (int i = 0, j = 0; i < targets.size(); i++) { int runLength = runLengths.get(i).intValue(); siblingsByTarget.add( Pair.of(targets.get(i).node(), mod.references().subList(j, j + runLength))); j += runLength; } }
@Override public void restore() throws TransformException { ItemList targets = mod.nearest(NodeTarget.class).targets(); values = new ArrayList<Pair<String, Item>>(targets.size()); for (Node node : targets.nodes()) { ItemList items = query.runOn(mod.scope(node.query())); if (items.size() != 1) throw new TransformException( "sort by value query did not select exactly one item: " + items); values.add(Pair.of(node.query().single("@xml:id").value(), items.get(0).toAtomicItem())); } }
@Override void resolveOrder(Mod.Builder modBuilder, Node node) throws TransformException { ItemList items = query.runOn(modBuilder.customScope(node.query())); if (items.size() != 1) throw new TransformException( "sort by value must select one value per target, but instead selected " + items.size() + ": " + items); modBuilder .supplement() .elem("sort-value") .attr("refid", node.query().single("@xml:id").value()) .text(items.get(0).value()) .end("sort-value"); }
@Override void resolveOrder(Mod.Builder modBuilder, Node node) throws TransformException { // TODO: see if we can resolve /id in global scope while keeping node context ItemList items = query.runOn(modBuilder.customScope(node.query())); if (items.size() != 1) throw new TransformException( "sort by corresponding node must select one node per target, but instead selected " + items.size() + ": " + items); Node proxy = items.get(0).node(); modBuilder.reference(proxy); modBuilder .supplement() .elem("sort-proxy") .attr( "position", proxy.query().single("count(preceding::*) + count(ancestor::*)").value()) .end("sort-proxy"); }
@Override void resolveOrder(Mod.Builder modBuilder, Node node) throws TransformException { ItemList siblings = query.runOn(modBuilder.customScope(node.query().single("..").query())); for (Node sibling : siblings.nodes()) { if (!node.query().single(".. is $_1/..", sibling).booleanValue()) throw new TransformException("query selected non-sibling node: " + sibling); modBuilder.reference(sibling); } modBuilder .supplement() .elem("sort-siblings") .attr("run-length", siblings.size()) .end("sort-siblings"); }