Magnolia 5.6 reached end of life on June 25, 2020. 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.
jsonfnUse 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. 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.
fromGet 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.fromChildNodesOfGet 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.appendFromGet 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.
downDefine 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()}
allowOnlyNodeTypesAllow 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()}
readNodeTypesAllow 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()}
childrenAsArraySelect 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.
insertCustomReplace 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.
addAllAdd all properties.
JsonBuilder addAll()
No arguments.
[#assign pageNode = cmsfn.contentByPath("/vinyl", "website") /]
${jsonfn.from(pageNode).addAll().print()}
addAdd 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()}
excludeExclude 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.
expandResolve 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.binaryLinkRenditionAdd 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.
inlineGet 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.
maskCharReplace 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()}
escapeBackslashEscapes 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()}
wrapForI18nEnsures 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
JsonBuilder wrapForI18n()
No arguments
[#assign cameraNode = cmsfn.contentByPath("/cameras/X-Pro2", "cameracollection") /]
${jsonfn.from(cameraNode).add("description").wrapForI18n().print()}
printThe 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()}