@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())); } }
/** * Compares results. * * @param expected expected result * @param returned returned result * @throws Exception exception */ private static void compare(final ItemList expected, final ItemList returned) throws Exception { // Compare response with expected result assertEquals("Different number of results", expected.size(), returned.size()); final long es = expected.size(); for (int e = 0; e < es; e++) { final Item exp = expected.get(e), ret = returned.get(e); if (!new DeepEqual().equal(exp, ret)) { final TokenBuilder tb = new TokenBuilder("Result ").addLong(e).add(" differs:\nReturned: "); tb.addExt(ret.serialize()).add("\nExpected: ").addExt(exp.serialize()); fail(tb.toString()); } } }
@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"); }
/** * Get no more than one item that matches the given query in the context of this object. * * @param query the query to match * @param params * @return the item that matches this query, or <code>Item.NULL</code> if none */ public Item optional(String query, Object... params) { ItemList result = executeQuery(query, ZERO_OR_ONE, params); assert result.size() <= 1 : "expected zero or one results, got " + result.size(); return result.size() == 0 ? Item.NULL : result.get(0); }
/** * Get the one and only item that matches the given query in the context of this object. * * @param query the query to match * @param params * @return the unique item that matches the query */ public Item single(String query, Object... params) { ItemList result = executeQuery(query, EXACTLY_ONE, params); assert result.size() == 1 : "expected single result, got " + result.size(); return result.get(0); }