Magnolia 5.7 reached extended end of life on May 31, 2022. Support for this branch is limited, see End-of-life policy. Please note that to cover the extra maintenance effort, this EEoL period is a paid extension in the life of the branch. Customers who opt for the extended maintenance will need a new license key to run future versions of Magnolia 5.7. If you have any questions or to subscribe to the extended maintenance, please get in touch with your local contact at Magnolia.
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.
Installation
jsonfn
templating functions are not bundled with preconfigured Magnolia bundles or webapps.
General usage of 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
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. Generating JSON
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
. |
Rendering JSON
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() }
- Node defining method
- Property defining methods
- Get the JSON String
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" }
Node defining methods
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
.
Method signatures
JsonBuilder from(Node node)
JsonBuilder from(ContentMap node)
Argument
node | required The node you want to work with. |
Example
[#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.
Method signature
JsonBuilder fromChildNodesOf(String workspaceName)
JsonBuilder fromChildNodesOf(ContentMap node)
JsonBuilder fromChildNodesOf(Node node)
Argument
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. |
Example
${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.
Method signatures
JsonBuilder from(String json, Node node)
JsonBuilder from(String json, ContentMap node)
Arguments
json | required The JSON string to which the new json gets appended to. |
node | required The node you want to work with. |
Example
[#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>
Node customizing methods
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.
Method signatures
JsonBuilder down(int level)
Arguments
level | required An integer defining the level of child nodes to get. Choose values >=1. |
Example
[#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.
Method signatures
JsonBuilder allowOnlyNodeTypes(String nodeTypesRegex)
Arguments
nodeTypesRegex
| required A regular expression that defines the wanted node types. |
Example
[#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.
Method signatures
JsonBuilder readNodeTypes(String nodeTypesRegex)
Arguments
nodeTypesRegex | required A regular expression to match the allowed node types. |
Example
[#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).
Method signatures
JsonBuilder childrenAsArray(String propertyName, String valueRegex)
Arguments
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 |
Example
[#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.
Method signatures
JsonBuilder insertCustom(String pathSuffix, String json)
Arguments
pathSuffix
| required The path to the node for which you want replace JSON. |
json
| required The JSON that replaces the regular JSON. |
Example
[#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.
Property defining methods
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.
Method signatures
JsonBuilder addAll()
Arguments
No arguments.
Example
[#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.
Method signatures
JsonBuilder add(String... property)
Arguments
property
| required The property to be included or a regular expression pattern to match properties. |
Example
[#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.
Method signatures
JsonBuilder exclude(String... property)
Arguments
property | required The property to be excluded or a regular expression pattern to match properties you want to exclude. |
Example
[#assign pageNode = cmsfn.contentByPath("/vinyl", "website") /]
${jsonfn.from(pageNode).addAll().exclude("jcr.*", "mgnl.*").print()}
Resolving referenced nodes and renditions
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.
Method signatures
JsonBuilder expand(String propertyName, String repository)
JsonBuilder expand(String propertyNameRegex, String targetRepository, String targetPropertyName)
Arguments
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. |
Example
[#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.- when expanding a property, it is not required to add it with the
#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.
Method signature
JsonBuilder binaryLinkRendition(String... variation)
Arguments
variation | required The image variation (rendition) name of the asset. |
Example
[#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.
Formatting, i18n and print
inline
Get the JSON string on one line.
Method signature
JsonBuilder inline()
Arguments
none
Example
[#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.
Method signature
JsonBuilder maskChar(char what, char replace)
Arguments
what | required The char to replace. |
replace
| required The replacement char. |
Example
[#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!
Method signature
JsonBuilder escapeBackslash()
Arguments
No arguments.
Example
[#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
Method signature
JsonBuilder wrapForI18n()
Arguments
No arguments
Example
[#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.
Method signature
JsonBuilder print()
Arguments
No arguments
Example
[#assign pageNode = cmsfn.contentByPath("/vinyl", "website") /]
${jsonfn.from(pageNode).addAll().exclude("mgnl.*", "jcr.*").print()}