Magnolia 6.1 reached end of life on March 31, 2021. This branch is no longer supported, see End-of-life policy.
jsonfn
templating functions generate JSON from JCR nodes in any workspace. This allows you to generate highly customized JSON without writing custom Java classes.
These templating functions are provided by the magnolia-jsonfn
module which is hosted in the https://github.com/magnolia-community/jsonfn repository. The jsonfn
templating functions originated in the neat-jsonfn
module, hosted on GitHub and developed by rah003.
jsonfn
templating functions are not bundled with preconfigured Magnolia bundles or webapps.
jsonfn
Use jsonfn
to generate JSON from JCR nodes. You can customize the JSON to suit your needs by combining methods.
Combine at least one node defining method with one property defining method. All property defining methods are applied to all nodes. Finish with the #print
method to get JSON as a string.
jsonfn
methods are provided by the
JsonTemplatingFunctions
Java class. These methods return a
JsonBuilder
object to apply on further methods, which in turn return the same JsonBuilder object. This allows the methods to be applied in an additive way.
To generate JSON:
Define the JCR node(s) to transform into JSON. | required | See Node defining methods. |
Define the JCR properties to be added to the JSON object. | required | See Property defining methods. |
Customize JSON, resolve referenced nodes and renditions, format. | optional | |
Generate the JSON string with the #print method. | required | See
print
. |
In your FreeMarker template render the JSON string directly in the output stream (or assign it to a JavaScript variable).
Example:
[#assign pageNode = cmsfn.contentByPath("/vinyl", "website") /]
${ jsonfn
.from(pageNode) .addAll().exclude("mgnl.*", "jcr.*") .print() }
Example output:
{ "@nodeType" : "mgnl:page", "@name" : "vinyl", "@link" : "/vinyl-site/", "hideInNav" : true, "@depth" : 1, "navigationTitle" : "Best vinyl", "windowTitle" : "Best vinyl", "@id" : "17ac0768-4337-4dda-a8da-223c036d299d", "title" : "Best vinyl", "@path" : "/vinyl" }
Select the JCR nodes to transform into JSON. All methods return a
JsonBuilder
object to apply to further methods.
from
Get JSON by a given
Node
or
ContentMap
.
JsonBuilder from(Node node)
JsonBuilder from(ContentMap node)
node | required The node you want to work with. |
[#assign contentMap = cmsfn.contentByPath("/comics", "website") /]
[#assign contentNode = cmsfn.asJCRNode(cmsfn.contentByPath("/vinyl", "website")) /]
[
${jsonfn
.from(contentMap).add("title").print()} ,
${jsonfn
.from(contentNode).add("title").print()}
]
#from
method can also handle the javax.jcr.Node as an argument.fromChildNodesOf
Get the child nodes of a given node or workspace. The given node can be a
Node
or a
ContentMap
. In the case of a workspace, the "technical" JCR root is not taken into account. The resultant JSON is an array (see example below).
Combine with the down
method if you want more than the direct children.
JsonBuilder fromChildNodesOf(String workspaceName)
JsonBuilder fromChildNodesOf(ContentMap node)
JsonBuilder fromChildNodesOf(Node node)
fromChildNodesOf(workspaceName) | |
workspaceName
| required The name of the workspace. |
fromChildNodesOf(node) | |
node | required The node from which the child nodes should be taken into account. |
${jsonfn
.fromChildNodesOf("website").down(2).allowOnlyNodeTypes("mgnl:page").add("title", "@path").print()}
mgnl:page
from the website
workspace down to level 2.appendFrom
Get JSON by a given
Node
or
ContentMap
and append it to a given JSON string. Further applied methods are only applied to the resultant JSON of the given node.
JsonBuilder from(String json, Node node)
JsonBuilder from(String json, ContentMap node)
json | required The JSON string to which the new json gets appended to. |
node | required The node you want to work with. |
[#assign damNode = cmsfn.contentByPath("/jolly-jumper", "dam") /]
[#assign damJson = jsonfn.from(damNode).down(2).add("@name").allowOnlyNodeTypes("mgnl:asset").inline().print()]
[#assign websiteNode = cmsfn.contentByPath("/vinyl", "website") /]
[#assign allJson = jsonfn.appendFrom(damJson, websiteNode).down(1).add("@path").allowOnlyNodeTypes("mgnl:page").inline().print() /]
<script>
var damJson = '${damJson}';
var allJson = '${allJson}';
</script>
These methods impact the resulting node structure. The methods are applied on a
JsonBuilder
object and return a JsonBuilder.
down
Define the level of child nodes to get.
JsonBuilder down(int level)
level | required An integer defining the level of child nodes to get. Choose values >=1. |
[#assign node = cmsfn.contentByPath("/", "website") /]
${jsonfn.from(node).add("@path").down(2).allowOnlyNodeTypes("mgnl:page").print()}
allowOnlyNodeTypes
Allow only node types by a given parameter (or regular expression). The method is applied during the #print
method and subnodes of excluded nodes go into the resulting JSON if not specifically excluded by the regular expression.
JsonBuilder allowOnlyNodeTypes(String nodeTypesRegex)
nodeTypesRegex
| required A regular expression that defines the wanted node types. |
[#assign damNode = cmsfn.contentByPath("/comics", "dam") /]
${jsonfn.from(damNode).down(2).allowOnlyNodeTypes("mgnl:asset").add("@nodeType", "@path").readNodeTypes("mgnl.*").print()}
readNodeTypes
Allow only node types by a given parameter (or regular expression). The method is applied during input phase and node types that are not defined by the regular expression will not be read. As a consequence, a node's subnodes are also skipped, even if they would have been allowed.
Use this method to, for instance, ensure you do not read (and process) JCR history or repository permissions that are also stored in repository. The purpose of the method is to ensure that you do not waste time processing something that would be discarded anyway.
JsonBuilder readNodeTypes(String nodeTypesRegex)
nodeTypesRegex | required A regular expression to match the allowed node types. |
[#assign damNode = cmsfn.contentByPath("/comics", "dam") /]
${jsonfn.from(damNode).down(2).readNodeTypes("mgnl:asset").add("@nodeType", "@path").readNodeTypes("mgnl.*").print()}
childrenAsArray
Select parent nodes by a property and a value to display their children as an array. The child nodes are organized in an array (see example below).
JsonBuilder childrenAsArray(String propertyName, String valueRegex)
propertyName
| required The name of the property used to select the parent node. |
valueRegex | required The value (or a regular expression matching the value) of the named |
[#assign damNode = cmsfn.contentByPath("/some-assets", "dam") /]
[#assign jsbTmp = jsonfn.from(damNode).readNodeTypes("mgnl.*").down(2).add("@nodeType", "@path") /]
${jsbTmp.print()}
/** below the children nodes of a mgnl:folder are organized within an array **/
${jsbTmp.childrenAsArray("@nodeType", "mgnl:folder").print()}
Line 3 renders the JSON without using arrays. Line 5 renders the child nodes of nodes of the type mgnl:folder
as arrays.
insertCustom
Replace JSON that is expected to be generated at a given path with given custom JSON.
JsonBuilder insertCustom(String pathSuffix, String json)
pathSuffix
| required The path to the node for which you want replace JSON. |
json
| required The JSON that replaces the regular JSON. |
[#assign websiteNodes = cmsfn.contentByPath("/vinyl", "website") /]
[#assign regularJsonObjects = jsonfn.from(websiteNodes).down(2).readNodeTypes("mgnl:page").add( "@path", "title")/]
${regularJsonObjects.print()}
/** **/
${regularJsonObjects.insertCustom("/vinyl/jazz",'{"bluenotes":true, "mind-blowing" : "sometimes", "max-bpm" : 145}').print()}
Line 3 renders the "regular" JSON. On line 5, the JSON of the node with the path /vinyl/jazz
is replaced with custom JSON.
Specify which properties of the JCR node should go into the JSON object. Combine inclusionary and exclusionary methods. The resultant set of properties is applied to all nodes, subnodes and resolved nodes, if the node has a value for the property. The methods are applied on a
JsonBuilder
object and return the JsonBuilder.
addAll
Add all properties.
JsonBuilder addAll()
No arguments.
[#assign pageNode = cmsfn.contentByPath("/vinyl", "website") /]
${jsonfn.from(pageNode).addAll().print()}
add
Add the wanted properties. You can pass one or many arguments that can be regular expressions.
JsonBuilder add(String... property)
property
| required The property to be included or a regular expression pattern to match properties. |
[#assign pageNode = cmsfn.contentByPath("/vinyl", "website") /]
${jsonfn.from(pageNode).add("@.*").print()}
/** --- **/
${jsonfn.from(pageNode).add("mgnl.*", "title").print()}
exclude
Exclude unwanted properties. You can pass one or many arguments that can be regular expressions.
JsonBuilder exclude(String... property)
property | required The property to be excluded or a regular expression pattern to match properties you want to exclude. |
[#assign pageNode = cmsfn.contentByPath("/vinyl", "website") /]
${jsonfn.from(pageNode).addAll().exclude("jcr.*", "mgnl.*").print()}
Resolve referenced nodes and image renditions. The methods are applied on a
JsonBuilder
object and return the JsonBuilder.
expand
Resolve nodes which are referenced by a property value.
JsonBuilder expand(String propertyName, String repository)
JsonBuilder expand(String propertyNameRegex, String targetRepository, String targetPropertyName)
expand(propertyName, repository) | |
propertyName
| required The name of the property which contains the reference to a node in another workspace. |
repository
| required The name of the repository which contains the node to be expanded. |
expand(propertyNameRegex, targetRepository, targetPropertyName) | |
propertyNameRegex
| required A regular expression that matches the name of the property which contains the reference to a node in another workspace. |
targetRepository
| required The name of the target repository which contains the node to be expanded. |
targetPropertyName
| required The name of the property of the referenced node. |
[#assign contentAppItemNode = cmsfn.contentByPath("/cameras/F3", "cameracollection") /]
/** node with references to other nodes **/
${jsonfn.from(contentAppItemNode).add("name", "maker", "categories", "images").print()}
/** expanding the referenced categories, images and maker **/
${jsonfn.from(contentAppItemNode).add("@link", "name")
.expand("maker", "cameracollection")
.expand("categories", "category", "jcr:uuid")
.expand("images", "dam")
.expand("image", "dam")
.print()}
Note:
.expand("categor.*", "category", "jcr:uuid")
could be replaced with .expand("categories", "category")
in the above example.#add
method.binaryLinkRendition
Add renditions for assets. This works only if the renditions (image variations) have been defined on the current Theme.
Each rendition is added as a property of the asset. The property name for a rendition follows this pattern: @rendition_<rendition-name>
. The value is a link.
If a rendition is not defined in the theme, the property is added, but the value points to the default link.
JsonBuilder binaryLinkRendition(String... variation)
variation | required The image variation (rendition) name of the asset. |
[#assign contentAppItemNode = cmsfn.contentByPath("/comics/belgian-comics/morris/lucky-luke/jolly-jumper/main", "website") /]
${jsonfn.from(contentAppItemNode).down(2).allowOnlyNodeTypes("mgnl.*")
.add("@nodeType", "image", "@link")
.expand("image", "dam")
.binaryLinkRendition("default","960","foobar")
.print()}
This example renders a component node which contains an image (which is expanded) and includes its renditions.
inline
Get the JSON string on one line.
JsonBuilder inline()
none
[#assign pageNode = cmsfn.contentByPath("/vinyl", "website") /]
[#assign jsonBuilder = jsonfn.fromChildNodesOf(pageNode).readNodeTypes("mgnl:page").down(2).add("title") /]
/** multiline **/
${jsonBuilder.print()}
/** single-line **/
${jsonBuilder.inline().print()}
This example renders a component node which contains an image (which gets expanded) and includes its renditions.
maskChar
Replace one char with another on property names.
JsonBuilder maskChar(char what, char replace)
what | required The char to replace. |
replace
| required The replacement char. |
[#assign pageNode = cmsfn.contentByPath("/comics/belgian-comics/morris/lucky-luke/jolly-jumper/in-love", "website") /]
[#assign jsonBuilder = jsonfn.from(pageNode).add("mgnl:last.*x") /]
${jsonfn.from(pageNode).add("mgnl:lastA.*").print()}
/** **/
${jsonfn.from(pageNode).add("mgnl:lastA.*").maskChar(':', '_').print()}
escapeBackslash
Escapes backslashes (\
) in the JSON. Use with care and only if strictly necessary. Typically backslashes are already escaped!
JsonBuilder escapeBackslash()
No arguments.
[#assign cameraNode = cmsfn.contentByPath("/cameras/X-Pro2", "cameracollection") /]
${jsonfn.from(cameraNode).add("description").escapeBackslash().print()}
wrapForI18n
Ensures that localized values are available and the values of the properties are set according to the current locale.
When the function is applied, the nodes are wrapped into I18nNodeWrapper .
JsonBuilder wrapForI18n()
No arguments
[#assign cameraNode = cmsfn.contentByPath("/cameras/X-Pro2", "cameracollection") /]
${jsonfn.from(cameraNode).add("description").wrapForI18n().print()}
print
The print
methods returns the JSON as a string. Always call this method at the end when you want to render the JSON.
JsonBuilder print()
No arguments
[#assign pageNode = cmsfn.contentByPath("/vinyl", "website") /]
${jsonfn.from(pageNode).addAll().exclude("mgnl.*", "jcr.*").print()}