Taxonomy Plugin Store Ancestor Keys Automatically
Default Taxonomy Field Stores Ancestor Information
As of version 15.3, a Taxonomy field type is available in the Document Type Editor. When used, taxonomy keys are stored in a JCR property that is defined there, typically by a developer.
When the Taxonomy Picker is used in a document, the picked categories will be stored in that multiple JCR property.
This feature can be very convenient when searching for documents based on a high level taxonomy category.
For example a document instance with a geography-based taxonomy field and two selected items would get:
/content/documents/myproject/content/example-doc/example-doc: myproject:mytaxonomy: [san-francisco, london] myproject:mytaxonomy__with_ancestors: [northamerica, usa, california, san-francisco, europe, uk, london]
Configure Taxonomy Mixin Field to Store Ancestor Information
Legacy Documentation (Taxonomy Mixin Field)
Below documentation applies to the legacy Taxonomy Mixin Field, from version 15.3.0.
The legacy, mixin-based, taxonomy field can be configured to store ancestor information besides the default hippotaxonomy:keys property (or the path defined by 'fieldPath', see "Extra Taxonomy Field".
To enable, set flag storeKeysWithAncestors to true in the DAO service.
The ancestor information is stored in multiple property hippotaxonomy:keyswithancestors, unless specified in fieldWithAncestorsPath.
/hippo:configuration/hippo:frontend/cms/cms-services/classificationDaoService: storeKeysWithAncestors: true // optional, defaults to hippotaxonomy:keyswithancestors fieldWithAncestorsPath: myproject:mycategories_withancestors
Groovy Script to Populate Ancestor Information on Existing Documents
Since taxonomy keys and ancestor keys are stored on save, it may be wanted to run an updater script to update existing documents accordingly without the need to open and save every document.
See below for an example script that may serve as base to do that.
package org.hippoecm.frontend.plugins.cms.admin.updater import org.hippoecm.repository.util.JcrUtils import org.onehippo.repository.update.BaseNodeUpdateVisitor import javax.jcr.Node import javax.jcr.NodeIterator import javax.jcr.RepositoryException import javax.jcr.Session import javax.jcr.query.Query import org.onehippo.taxonomy.api.TaxonomyNodeTypes /** * Groovy script to populate a taxonomy property for storing all ancestor keys, based on an existing taxonomy property. * * XPath query: //element(*, myproject:contentdocument) * Parameters: { "keysProperty" : "hippotaxonomy:keys", * "keysWithAncestorsProperty" : "hippotaxonomy:keyswithancestors" } */ class PopulateTaxonomyKeysWithAncestors extends BaseNodeUpdateVisitor { boolean logSkippedNodePaths() { return false } boolean skipCheckoutNodes() { return false } Node firstNode(final Session session) throws RepositoryException { return null } Node nextNode() throws RepositoryException { return null } boolean doUpdate(Node node) { def keysProperty = parametersMap["keysProperty"] def keysWithAncestorsProperty = parametersMap["keysWithAncestorsProperty"] String[] keys = JcrUtils.getMultipleStringProperty(node, keysProperty, null) if (keys == null) { log.debug "Not recreating ${keysWithAncestorsProperty}: no ${keysProperty} on node ${node.path}" return false } log.debug "Recreating ${keysWithAncestorsProperty} based on ${keysProperty}=${keys} on node ${node.path}" final def keysWithAncestors = new LinkedHashSet<>(); def queryMgr = node.getSession().getWorkspace().getQueryManager() for (def key : keys) { def ancestors = getKeyWithAncestors(key, queryMgr) log.debug " adding values ${ancestors}" keysWithAncestors.addAll(ancestors) } String[] values = keysWithAncestors.toArray(new String[0]) node.setProperty(keysWithAncestorsProperty, values) return true } boolean undoUpdate(Node node) { throw new UnsupportedOperationException('Updater does not implement undoUpdate method') } def getKeyWithAncestors(def key, def queryMgr) { def keyWithAncestors = new LinkedList() def statement = "content/taxonomies//element(*, hippotaxonomy:category)[hippotaxonomy:key = '" + key + "']" def query = queryMgr.createQuery(statement, Query.XPATH) final NodeIterator nodes = query.execute().nodes // there should be only one (unique key) if (nodes.hasNext()) { def cat = nodes.nextNode() // only category nodes up the tree have the key property while (cat.hasProperty(TaxonomyNodeTypes.HIPPOTAXONOMY_KEY)) { keyWithAncestors.add(cat.getProperty(TaxonomyNodeTypes.HIPPOTAXONOMY_KEY).string) cat = cat.parent } } else { log.debug("No category node found by key ${key}") } // same order as MixinClassificationDaoPlugin Collections.reverse(keyWithAncestors) return keyWithAncestors; } }