How can I retrieve the full JSONPath of a specific field/node in Altova MapForce?
I’m working with Altova MapForce to map JSON data and need a function that takes a field/node as input and returns its full JSONPath string. For example, given this JSON:
{
"user": {
"profile": {
"name": "John Doe",
"contact": {
"email": "john@example.com"
}
}
}
}
Passing the “email” field should return: $.user.profile.contact.email
Does MapForce expose a built-in function to get a node’s full JSONPath during mapping? If not, is it possible to implement this with a custom Java function - and what would be the recommended approach or API to access node/path information from a custom function? Any implementation tips or links to relevant Altova MapForce documentation would be helpful.
Altova MapForce doesn’t expose a single built‑in “full JSONPath” extractor — you build the path yourself in the mapping (for example by using the core node functions like node-name / local-name and a recursive User‑Defined Function (UDF)). You can import a custom Java helper, but imported Java methods only get the parameters you map to them (they don’t receive MapForce’s internal node handles), so the most portable solution is to assemble the JSONPath inside MapForce and pass that string on or into a Java helper when needed.
Contents
- Does MapForce provide a built-in altova mapforce jsonpath function?
- Implementing a custom mapforce jsonpath UDF (node-name + recursion)
- Java custom functions: can a custom Java UDF access node/path info?
- Implementation example: recursive algorithm and MapForce pattern
- Edge cases and practical tips (arrays, duplicates, performance)
- Sources
- Conclusion
Does MapForce provide a built-in altova mapforce jsonpath function?
Short answer: no. MapForce provides node inspection functions — for example, the core node library exposes node-name, local-name and related helpers that let you read a node’s name or QName — but there is no single built‑in function that returns the full dotted JSONPath (like $.user.profile.contact.email) for an arbitrary node automatically. See the core node functions reference for details on what MapForce exposes: https://www.altova.com/manual/Mapforce/mapforcebasic/mff_lib_core_node.html.
MapForce also supports dynamic node access (runtime access to children and attributes) and dynamic node names, which you can use while building a path string as you traverse the structure: https://www.altova.com/manual/Mapforce/mapforcebasic/mff_node_access_get.html and https://www.altova.com/manual/Mapforce/mapforcebasic/mff_node_access.html. But putting those pieces together so they produce a full JSONPath is something you do in the mapping (graphically), normally via a UDF or recursive mapping pattern — MapForce doesn’t supply a one-liner that returns “$.a.b.c” for you.
Implementing a custom mapforce jsonpath UDF (node-name + recursion)
Recommendation: implement a recursive User‑Defined Function (UDF) that accumulates a path prefix as it descends the JSON structure, then returns the path when it finds the target field. MapForce UDFs are the most direct, portable solution and generate clean code if you later export the mapping to XSLT / Java / C++ / etc. See the UDF documentation for how to create and wire UDF components: https://www.altova.com/manual/Mapforce/mapforcebasic/mf_func_udf.html.
A workable UDF pattern (high level)
- UDF inputs:
- sourceNode (object/array node or the node to inspect)
- currentPath (string) — initial value “$”
- targetName (optional string) — the field name you’re searching for (e.g., “email”)
- UDF output:
- path (string) — the JSONPath(s) found (could be a single string or a sequence)
- Inside the UDF:
- For each child property of sourceNode:
- get the child name via node-name(child) or local-name if you prefer the local part
- build newPath = currentPath == “.” + childName : currentPath + “.” + childName
- if child is a leaf (primitive) and childName == targetName, emit newPath
- if child is an object/array, call the UDF recursively with (child, newPath, targetName)
- Call pattern: invoke UDF with the source root and “$” as starting path; capture output and filter/select the path you need.
Pseudo‑code for the UDF (easy to translate into a MapForce UDF graph)
function findPath(node, path, targetName):
for each child in node:
name = node-name(child)
newPath = (path == "$") ? "$." + name : path + "." + name
if not hasChildren(child) and name == targetName:
yield newPath
else:
for result in findPath(child, newPath, targetName):
yield result
How this fits your example JSON
- Call findPath(root, “$”, “email”)
- Traversal will emit:
- $.user.profile.contact.email
- You can stop at first match, or return all matches if the name appears multiple times.
Why UDFs are recommended
- They let you stay inside MapForce so the generated output (XSLT, Java, etc.) already contains the path logic.
- You can wire MapForce functions like node-name / local-name directly into the UDF graph (see node functions doc): https://www.altova.com/manual/Mapforce/mapforcebasic/mff_lib_core_node.html.
- No need to pass whole JSON text into an external routine (which hurts performance and is error prone).
Java custom functions: can a custom Java UDF access node/path info?
Short answer: you can import custom Java helpers into MapForce, but they do not automatically get MapForce’s internal node objects or ancestry. The MapForce Java import process is documented here; you add a compiled Java .class to the mapping libraries: https://www.altova.com/manual/Mapforce/mapforceenterprise/mff_custom_func_java_example.html.
Two realistic Java-based approaches
- Pass path components from MapForce into Java
- Let the MapForce UDF or mapping assemble the path parts (or the full JSONPath string) and pass that string to your Java method for formatting, validation or other enrichment.
- This is the simplest and most robust pattern because your Java method receives plain strings/numbers (which MapForce maps cleanly).
- Pass the full JSON (or node content) into Java and search there
- You can pass a JSON string to a custom Java method, parse it inside Java (Jackson, org.json, etc.) and compute the JSONPath by searching for the target key or value.
- Downsides: slower (serialization + parse), ambiguous when the same key appears multiple times, and more complex to integrate.
- Use this only if you have a compelling reason to do the search in Java rather than in the MapForce mapping itself.
Example (Java pseudocode using Jackson — you would need to add Jackson to your Java runtime if you choose this route):
public static String findJsonPath(JsonNode node, String targetKey) {
return findJsonPath(node, targetKey, "$");
}
private static String findJsonPath(JsonNode node, String targetKey, String path) {
if (node.isObject()) {
Iterator<String> fields = node.fieldNames();
while (fields.hasNext()) {
String name = fields.next();
JsonNode child = node.get(name);
String newPath = path.equals("$") ? "$." + name : path + "." + name;
if (name.equals(targetKey) && !child.isContainerNode()) return newPath;
String r = findJsonPath(child, targetKey, newPath);
if (r != null) return r;
}
} else if (node.isArray()) {
for (int i = 0; i < node.size(); i++) {
JsonNode child = node.get(i);
String newPath = path + "[" + i + "]";
String r = findJsonPath(child, targetKey, newPath);
if (r != null) return r;
}
}
return null;
}
Remember: to use a Java helper like this you must pass in the JSON string (or a structure MapForce can map to Java types), and you’ll pay the parsing cost.
Importing the Java class into MapForce
- Compile your helper to a .class (or package to a JAR).
- In MapForce, add it to the Libraries window (Add/Remove Libraries); if you want to preview Java-transformation, set transformation language to Java so the library shows up (see the example page): https://www.altova.com/manual/Mapforce/mapforceenterprise/mff_custom_func_java_example.html.
- MapForce will let you call the public static methods from your mapping; map appropriate parameters (strings, numbers, arrays) into the method.
Implementation example: recursive algorithm and MapForce pattern
Practical MapForce wiring (summary)
- In the mapping, create a UDF called findPath with inputs (node, prefix, target).
- Inside the UDF, connect the node children (repeatable occurrence) to the recursive structure. Use node-name to extract each child’s name and use concat to append to the prefix.
- Use a conditional (if/choose) to emit the path when name == target and child is a leaf.
- Wire the UDF output back to a target text element or to a parameter passed to Java if you prefer post-processing.
A quick XSLT-style illustration (shows the algorithm — MapForce can generate XSLT, so this is close to the generated code):
<xsl:template name="recurse">
<xsl:param name="node"/>
<xsl:param name="path" select="'$'"/>
<xsl:param name="target"/>
<xsl:for-each select="$node/*">
<xsl:variable name="name" select="name()"/>
<xsl:variable name="newPath" select="concat($path, '.', $name)"/>
<xsl:if test="not(*) and $name = $target">
<xsl:value-of select="$newPath"/>
</xsl:if>
<xsl:call-template name="recurse">
<xsl:with-param name="node" select="."/>
<xsl:with-param name="path" select="$newPath"/>
<xsl:with-param name="target" select="$target"/>
</xsl:call-template>
</xsl:for-each>
</xsl:template>
Call it with the document root and target = “email” to get $.user.profile.contact.email.
Debugging tips
- Preview mapping output in MapForce for small samples while you build the UDF.
- Log or emit intermediate prefixes (e.g., $.user, $.user.profile) to verify the concatenation logic.
- Start with a tiny JSON and expand when the approach works.
Edge cases and practical tips (arrays, duplicates, performance)
- Arrays: Do you want indices (
[0]) or a wildcard ([*])? If you need a concrete index, your mapping/UDF must capture the item position while iterating. That may require a counter or position value. If exact index is unnecessary, emit[*]or omit the bracket. - Duplicate keys: If the same key appears multiple times in different branches, searching by key name alone returns the first match — add additional filters (parent name, value, an ID field) to identify the correct instance.
- Namespaces / prefixes: For XML-to-JSON cases, node-name returns the QName including prefix; use local-name if you want the unprefixed name: https://www.altova.com/manual/Mapforce/mapforcebasic/mff_lib_core_node.html.
- Performance: A full traversal that records every node’s path can be expensive on large JSON documents. If you only need paths for a few known branches, build those branches’ paths directly instead of scanning the entire tree.
- Generated code: If you export the mapping to Java and still want to customize the path function, you can either (a) implement the path search in MapForce (preferred) or (b) export the mapping, then modify the generated Java to include a specialized path helper — but that loses some portability.
- Uniqueness: If you pass values to a Java helper to identify a node (e.g., search for a specific email value), be careful—non-unique values will cause ambiguous results.
Sources
- https://www.altova.com/manual/Mapforce/mapforcebasic/mff_node_access.html
- https://www.altova.com/manual/Mapforce/mapforcebasic/mff_lib_core_node.html
- https://www.altova.com/manual/Mapforce/mapforcebasic/mff_node_access_get.html
- https://www.altova.com/manual/Mapforce/mapforcebasic/mf_func_udf.html
- https://www.altova.com/manual/Mapforce/mapforceenterprise/mff_custom_func_java_example.html
Conclusion
There isn’t a built‑in “altova mapforce jsonpath” getter — use node-name (or local-name) together with a recursive User‑Defined Function (UDF) to assemble full JSONPath strings during mapping, and only use a custom Java helper when you either need heavy post‑processing or you accept passing path components or serialized JSON into Java. This approach is portable, debuggable, and fits the MapForce model (UDFs + core node functions) much better than trying to rely on an undocumented runtime API.