CIRCUITAN ADOBE DEVELOPER EVENTPRESENTED BY CITYTECH, INC.Use SlingQuery andwalk the tree with ease
Tomek Rękawek, Cognifide@TomaszRekawek
Sling APIResource parent = myResource.getParent(); for (Resource child : parent.getChildren()) { if (child.adaptTo(ValueMap.class).containsKey("myProperty")) { //... }}
efficient, especially for denormalized and well-structured content[1]easy to usebut:
a lot of while()s, iterators and nullcheckscode complexity is growing fast
[1] Efficient content structures and queries in CRX
Sling exampleFind the first ancestor with a given template.
String path = "/content/geometrixx/en/products/triangle/jcr:content/par";String homeTemplate = "/apps/geometrixx/templates/homepage";
Resource resource = resourceResolver.getResource(path);while ((resource = resource.getParent()) != null) { if (!resource.isResourceType("cq:Page")) { continue; } ValueMap map = resource.adaptTo(ValueMap.class); String cqTemplate = map.get("jcr:content/cq:template"); if (homeTemplate.equals(cqTemplate)) { break; }}resource.getPath();
SlingQuery exampleimport static com.cognifide.sling.query.api.SlingQuery.$;Resource resource = getResource("/content/geometrixx/en/products/triangle/jcr:content/par");
$(resource) .closest("cq:Page[jcr:content/cq:template=/apps/geometrixx/templates/homepage]")
$() is a valid method name in Java,it wraps resource(s) into an iterable SlingQuerycollectioneach method transforms the existing collectioninto a new one
API inspired by jQuery
Get all text componentsfrom the parsysr = getResource("/content/geometrixx/en/jcr:content/rightpar/teaser")
SlingQuery collection = $(r) .closest("cq:PageContent") .find("foundation/components/parsys#par") .children("foundation/components/text")
for (Resource c : collection) { println c.path}
each method returns new collectionSlingQuery object implements Iterable
Breadcrumbsr = getResource("/content/geometrixx/en/products/mandelbrot/overview/jcr:content/par")
Iterable<Page> breadcrumbs = $(r) .parents("cq:Page") .not("[jcr:content/hideInNav=true]") .map(Page.class)
for (Page p : breadcrumbs) { println p.title}
map() method creates a new Iterable<>adapting each resource to a given classresource.adaptTo(Page.class)approach compatible with Sling Models
Selector stringr = getResource("/content/geometrixx/en/products/mandelbrot")
$(r) .children("cq:PageContent") .children("foundation/components/parsys") .children("#title[jcr:title=Best in class][type=large]:first")
selector formatresource type or node type#resource-nameattributes in []modifiers, each prepended by :
all elements are optional
Advanced selectorsr = getResource("/content/geometrixx")
$(r) .find("[text*=square]:not(cq:PageContent):first") .closest("cq:Page") .find("#title, #image, #par:parent")
:not() accepts any valid selector:not(:not(:not(:first)))
:parent - only resources having childrenthere is a number of operators for square bracketsalternatives can be separated with a comma
Random imagernd = new java.util.Random()r = getResource("/content/dam/geometrixx/travel")
$(r) .children("dam:Asset") .filter({ rnd.nextFloat() > 0.9 } as Predicate) .first()
in Java it'd look like this:// ... .filter(new Predicate<Resource>() { @Override public boolean accepts(Resource resource) { return rnd.nextFloat() > 0.9; } });
Siblings but not mer = getResource("/content/geometrixx/en/products/mandelbrot/jcr:content/par/image")
myPage = $(r).closest("cq:Page")
result = myPage .siblings("cq:Page") .not(myPage)
the SlingQuery collection is immutableeach method returns a new collection
any Iterable<Resource> may be used as a filter
Find all pages withgiven template$(resourceResolver) .find("cq:PageContent[cq:template=/apps/geometrixx/templates/homepage]") .parent()
$(resourceResolver) creates a collectioncontaining /find() iterates over the whole subtree
Search strategyr = getResource("/content/geometrixx/en")
result = $(r) .searchStrategy(DFS) .find("cq:Page")
for (Resource c : result) { println c.path}
strategies: DFS, BFS, QUERYQUERY tries to rewrite find() selector into JCR-SQL2
the result is filtered once more
Find method vs JCRfind() is powerful but may be dangerousit should be used only for small subtreesif you want to query a large space, use JCR-SQL[2]or XPathif your SlingQuery processes more than 100resources, you'll get a warning in the logs:
28.05.2014 13:35:49.942 *WARN* [0:0:0:0:0:0:0:1 [1401276949857] POST /bin/groovyconsole/post.json HTTP/1.1] SlingQuery Number of processed resources exceeded 100. Consider using a JCR query instead of SlingQuery. More info here: http://git.io/h2HeUQ
Lazinessresult = $(resourceResolver) .searchStrategy(DFS) .find() .slice(10, 20)
result.toString()
we don't query resources unless we need theminvoking the SlingQuery method adds a newfunction to the chainfunctions are executed by the final iterator (likethe one created by the for() loop)all functions are lazy
expect the last() function
Resourcescode & docs
global Maven repository
https://github.com/Cognifide/Sling-Query
<dependency> <groupId>com.cognifide.cq</groupId> <artifactId>sling-query</artifactId> <version>1.4.4</version></dependency>
Questions?
Thank you!