← Back to list

AEM — Script for Property and Value Finder Based on Resource Type and Root Page Path

When working with data validation or content, it’s often necessary to verify that certain property names and values exist OR not exist and…

Imran Khan · 2025-05-21 17:49 · 7 claps · 8.1 min read
#aem #adobe-experience-manager #aem-property-finder #aem-value-finder #aemasacloudservice
Open on Medium ↗

AEM — Script for Property and Value Finder Based on Resource Type and Root Page Path

When working with data validation or content, it’s often necessary to verify that certain property names and values exist OR not exist and behave as expected.

To streamline this process, developed a generic, reusable script designed to handle common search scenarios efficiently. This script can be easily adapted and integrated into various projects for quick checks and validations.

Every project, regardless of size or complexity, will likely require this type of validation at some point. Having a ready-to-use script like this helps avoid repetitive coding and ensures consistency across teams and environments.

It covers all generic senarios and feel free to customize and extend the script to fit your particular project needs.

Below inline generic script/code will allow us to validate the following search scenarios based on root page path, resource type, property names and values:

  • Exact match of property name Exist or NOT
  • Exact match of property name and value
  • Exact match of property name and contains value

Scenarios

The script supports the following key use cases:

Exact Match — Property Name Exists or Not:

Quickly determine whether a specific property name is present in the data structure or configuration.

Property Not Exist: Find out node names if given property Not Exist for particular resource type:

http://localhost:4502/services/findnodes?rootPagePath=/content/we-retail&resourceType=weretail/components/content/heroimage&propertyName=useFullWidth&existNotExist=notExist

Property Exist: Find out node names if given property Exist for particular resource type irrespective of value.

http://localhost:4502/services/findnodes?rootPagePath=/content/we-retail&resourceType=weretail/components/content/heroimage&propertyName=useFullWidth&existNotExist=exist

Exact Match — Property Name and Value:

Ensure that a property not only exists but also holds the exact value you’re expecting.

http://localhost:4502/services/findnodes?rootPagePath=/content/we-retail&resourceType=weretail/components/content/heroimage&propertyName=useFullWidth&propertyValue=true

Exact Match — Property Name and Contains Value:

Validate that a property contains a specific substring or partial value, helpful for pattern-based validations.

http://localhost:4502/services/findnodes?rootPagePath=/content/we-retail&resourceType=weretail/components/content/title&propertyName=jcr:title&propertyValue=Discover&valueSearchType=contains

Java Code Script

Copy and paste the recursive code snippet below into your project, then access the provided URL to verify whether the we-retail content hierarchy is present.

If the we-retail content is not available in your environment, update the request parameters to match your project’s specific structure.

http://localhost:4502/services/findnodes?rootPagePath=/content/we-retail&resourceType=weretail/components/content/heroimage&propertyName=useFullWidth&existNotExist=exist

import com.adobe.aemds.guide.utils.JcrResourceConstants;
import com.adobe.granite.rest.Constants;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.PageManager;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.HttpConstants;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

@Component(
        immediate = true,
        service = Servlet.class,
        property = {
                "sling.servlet.extensions=json",
                "sling.servlet.paths=/services/findnodes",
                "sling.servlet.methods="+ HttpConstants.METHOD_GET
        }
)
public class OpenInNewTabServlet extends SlingAllMethodsServlet {

    private final Logger LOGGER = LoggerFactory.getLogger(OpenInNewTabServlet.class);

    /*
        Property Not Exist
        http://localhost:4502/services/findnodes?rootPagePath=/content/we-retail&resourceType=weretail/components/content/heroimage&propertyName=useFullWidth&existNotExist=notExist

        Property Exist
        http://localhost:4502/services/findnodes?rootPagePath=/content/we-retail&resourceType=weretail/components/content/heroimage&propertyName=useFullWidth&existNotExist=exist

        Property Exist && Having Value
        http://localhost:4502/services/findnodes?rootPagePath=/content/we-retail&resourceType=weretail/components/content/heroimage&propertyName=useFullWidth&propertyValue=true

        Property Exist && Contains Value
        http://localhost:4502/services/findnodes?rootPagePath=/content/we-retail&resourceType=weretail/components/content/title&propertyName=jcr:title&propertyValue=Discover&valueSearchType=contains
     */

    // Below are REQUIRED parameters.
    private static final String ROOT_PAGE_PATH_PARAM = "rootPagePath";
    private static final String RESOURCE_TYPE_PARAM = "resourceType";
    private static final String PROPERTY_NAME_PARAM = "propertyName";

    // Below are all the OPTIONAL parameters.
    // This is an optional  parameter to pass if value need to get check.
    private static final String PROPERTY_VALUE_PARAM = "propertyValue";

    // valueSearchType = contains ; This is an option parameter is required only for checking if value contains.
    private static final String PROPERTY_VALUE_SEARCH_TYPE = "valueSearchType";

    /*
        This is an optional parameter to check property key name exists or not
        excludeInclude = exist OR excludeInclude = notExist.
     */
    private static final String EXIST_NOT_EXIST = "existNotExist";

    @Reference
    private PracticePathUtilsService practicePathUtilsService;

    @Override
    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {

        // Collect values from all request Parameters
        String rootPagePath = request.getParameter(ROOT_PAGE_PATH_PARAM);
        String resourceType = request.getParameter(RESOURCE_TYPE_PARAM);
        String propertyName = request.getParameter(PROPERTY_NAME_PARAM);
        String propertyValue = request.getParameter(PROPERTY_VALUE_PARAM);
        String existNotExist = request.getParameter(EXIST_NOT_EXIST);
        String valueSearchType = request.getParameter(PROPERTY_VALUE_SEARCH_TYPE);

        if (rootPagePath == null || rootPagePath.isEmpty()) {
            response.sendError(SlingHttpServletResponse.SC_BAD_REQUEST, "Root page path parameter is required.");
            return;
        }

        if (resourceType == null || resourceType.isEmpty()) {
            response.sendError(SlingHttpServletResponse.SC_BAD_REQUEST, "Resource type parameter is required.");
            return;
        }

        if (propertyName == null || propertyName.isEmpty()) {
            response.sendError(SlingHttpServletResponse.SC_BAD_REQUEST, "Property name parameter is required.");
            return;
        }

        PrintWriter out = getPrintWriter(response, resourceType, propertyName, existNotExist, propertyValue, valueSearchType);

        List<String> componentNodes = findComponentsByResourceTypeWithoutProperty(rootPagePath,
                resourceType, propertyName, propertyValue, existNotExist, valueSearchType, out);

        out.println("</table>");
        out.println("</br>");
        out.println("<h3> Total Results : " + componentNodes.size() + " </h3> ");
        out.close();
    }

    private List<String> findComponentsByResourceTypeWithoutProperty(String rootPagePath, String resourceType,
        String propertyName, String propertyValue, String existNotExist, String valueSearchType, PrintWriter out) {
        List<String> componentNodes = new ArrayList<>();
        ResourceResolver resourceResolver = practicePathUtilsService.getSystemUserResourceResolver();
        PageManager pageManager = resourceResolver.adaptTo(PageManager.class);

        try {
            Page rootPage = pageManager != null ? pageManager.getPage(rootPagePath) : null;
            if (rootPage != null) {
                Node rootPageNode = resourceResolver.getResource(rootPagePath).adaptTo(Node.class);
                if (null != rootPageNode) {
                    findComponentsRecursively(resourceResolver, rootPageNode, componentNodes,
                            resourceType, propertyName, propertyValue, existNotExist, valueSearchType, out);
                }
            }
        } catch (RepositoryException e) {
            LOGGER.error("Error while searching for components: ", e);
        }

        return componentNodes;
    }

    private void findComponentsRecursively(ResourceResolver resolver, Node node, List<String> componentNodes, String resourceType,
       String propertyName, String propertyValue, String existNotExist, String valueSearchType, PrintWriter out) throws RepositoryException {
        if (node.hasProperty(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY) &&
                node.getProperty(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY).getString().equals(resourceType)) {
            boolean hasProperty = node.hasProperty(propertyName);
            validateConditions(resolver, node, componentNodes, propertyName, propertyValue, existNotExist, valueSearchType, out, hasProperty);
        }

        NodeIterator nodeIterator = node.getNodes();
        while (nodeIterator.hasNext()) {
            Node childNode = nodeIterator.nextNode();
            findComponentsRecursively(resolver, childNode, componentNodes, resourceType,
                propertyName, propertyValue, existNotExist, valueSearchType, out);
        }
    }

    private void validateConditions(ResourceResolver resolver, Node node, List<String> componentNodes, String propertyName, String propertyValue, String existNotExist, String valueSearchType, PrintWriter out, boolean hasProperty) throws RepositoryException {
        if (hasProperty && StringUtils.isNotEmpty(propertyValue)) {
                if (StringUtils.equalsIgnoreCase("contains", valueSearchType) &&
                    StringUtils.contains(node.getProperty(propertyName).getValue().getString(), propertyValue)) {
                    collectValuesInList(resolver, node, componentNodes, out);
                } else if (StringUtils.equalsIgnoreCase(node.getProperty(propertyName).getValue().getString(), propertyValue)) {
                    collectValuesInList(resolver, node, componentNodes, out);
                }
        } else if (StringUtils.isNotEmpty(existNotExist) && StringUtils.isEmpty(propertyValue)){
            if (existNotExist.equalsIgnoreCase("notExist") && !hasProperty ||
                    existNotExist.equalsIgnoreCase("exist") && hasProperty) {
                collectValuesInList(resolver, node, componentNodes, out);
            }
        }
    }

    private Page getPageFromNode(ResourceResolver resolver, Node node) throws RepositoryException {
        Resource pageResource = resolver.getResource(node.getPath());
        PageManager pageManager = resolver.adaptTo(PageManager.class);
        return pageManager != null ? pageManager.getContainingPage(pageResource) : null;
    }

    private void collectValuesInList(ResourceResolver resolver, Node node,
        List<String> componentNodes, PrintWriter out) throws RepositoryException {
        Page currentPage = getPageFromNode(resolver, node);
        String pageName = null != currentPage ? currentPage.getName() : StringUtils.EMPTY;
        out.println("<tr><td>" + (componentNodes.size() + 1) + "</td><td>" + pageName + "</td><td> " + node.getName() + "</td><td>" + node.getPath() + "</td></tr>");
        componentNodes.add(pageName + " - " + node.getName() + " - " + node.getPath());
    }

    private static PrintWriter getPrintWriter(SlingHttpServletResponse response, String resourceType, String propertyName, String existNotExist, String propertyValue, String valueSearchType) throws IOException {
        response.setContentType(Constants.CT_TEXT_HTML);
        PrintWriter out = response.getWriter();
        out.println("<html><head><title>Response</title></head><body>");
        out.println("<h1>Search Results</h1>");
        out.println("<h3> Resource Type : " + resourceType + " </h3> ");
        out.println("<h3> Property Name : " + propertyName + " </h3> ");

        if (StringUtils.isNotEmpty(existNotExist)) {
            if (StringUtils.equalsIgnoreCase(existNotExist, "exist")) {
                out.println("<h3> Property Exists OR Not : Exists </h3> ");
            } else {
                out.println("<h3> Property Exists OR Not : Not Exists </h3> ");
            }
        }

        if (StringUtils.isNotEmpty(propertyValue)) {
            out.println("<h3> Property Value : " + propertyValue + " </h3> ");

            if (StringUtils.isNotEmpty(valueSearchType)) {
                out.println("<h3> Search Type : " + valueSearchType + " </h3> ");
            }
        }
        out.println("</br>");
        out.println("<table border='1' style='border-collapse: collapse;'>");
        out.println("<tr><th>No.</th><th>Page Name</th><th>Node Name</th><th>Node Path</th></tr>");
        return out;
    }
}

Request Parameters:

Required Parameters:

// Below are the REQUIRED request parameters: rootPagePath=/content/we-retail resourceType=weretail/components/content/heroimage propertyName=useFullWidth

// Below are all the OPTIONAL request parameters.

// Optional parameter for just to check given property exists or not existNotExist = exist OR existNotExist = notExist

// Optional parameter to pass if value need to get check. propertyValue=Accessibility Text

// Optional parameter only for checking if value contains passed keyword. valueSearchType=contains

OUTPUT:

http://localhost:4502/services/findnodes?rootPagePath=/content/we-retail&resourceType=weretail/components/content/heroimage&propertyName=useFullWidth&existNotExist=exist

Multi-field Property Name and Value Search

Below is the code to search property and its value present as part of component’s multi-field.

SAMPLE URL:http://localhost:4502/services/findnodes?rootPagePath=/content/we-retail&resourceType=weretail/components/content/heroimage&propertyName=useFullWidth&existNotExist=notExist&multiFieldNodeName=multifieldname

import com.adobe.aemds.guide.utils.JcrResourceConstants;
import com.adobe.granite.rest.Constants;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.PageManager;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.HttpConstants;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

@Component(
        immediate = true,
        service = Servlet.class,
        property = {
                "sling.servlet.extensions=json",
                "sling.servlet.paths=/services/findnodes",
                "sling.servlet.methods="+ HttpConstants.METHOD_GET
        }
)
public class OpenInNewTabServlet extends SlingAllMethodsServlet {

    private final Logger LOGGER = LoggerFactory.getLogger(OpenInNewTabServlet.class);

    /*
        Property Not Exist
        http://localhost:4502/services/findnodes?rootPagePath=/content/we-retail&resourceType=weretail/components/content/heroimage&propertyName=useFullWidth&existNotExist=notExist&multiFieldNodeName=multifieldname

        Property Exist
        http://localhost:4502/services/findnodes?rootPagePath=/content/we-retail&resourceType=weretail/components/content/heroimage&propertyName=useFullWidth&existNotExist=exist&multiFieldNodeName=multifieldname

        Property Exist && Having Value
        http://localhost:4502/services/findnodes?rootPagePath=/content/we-retail&resourceType=weretail/components/content/heroimage&propertyName=useFullWidth&propertyValue=true&multiFieldNodeName=multifieldname

        Property Exist && Contains Value
        http://localhost:4502/services/findnodes?rootPagePath=/content/we-retail&resourceType=weretail/components/content/title&propertyName=jcr:title&propertyValue=Discover&valueSearchType=contains&multiFieldNodeName=multifieldname
     */

    // Below are REQUIRED parameters.
    private static final String ROOT_PAGE_PATH_PARAM = "rootPagePath";
    private static final String RESOURCE_TYPE_PARAM = "resourceType";
    private static final String PROPERTY_NAME_PARAM = "propertyName";

    // Below are all the OPTIONAL parameters.
    // This is an optional  parameter to pass if value need to get check.
    private static final String PROPERTY_VALUE_PARAM = "propertyValue";

    // valueSearchType = contains ; This is an option parameter is required only for checking if value contains.
    private static final String PROPERTY_VALUE_SEARCH_TYPE = "valueSearchType";

    // NOTE: Pass this request parameter only ina case of multi-field property name and value search
    private static final String MULTI_FIELD_NODE_NAME = "multiFieldNodeName";

    /*
        This is an optional parameter to check property key name exists or not
        excludeInclude = exist OR excludeInclude = notExist.
     */
    private static final String EXIST_NOT_EXIST = "existNotExist";

    @Reference
    private PracticePathUtilsService practicePathUtilsService;

    @Override
    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {

        String rootPagePath = request.getParameter(ROOT_PAGE_PATH_PARAM);
        String resourceType = request.getParameter(RESOURCE_TYPE_PARAM);
        String propertyName = request.getParameter(PROPERTY_NAME_PARAM);
        String propertyValue = request.getParameter(PROPERTY_VALUE_PARAM);
        String existNotExist = request.getParameter(EXIST_NOT_EXIST);
        String valueSearchType = request.getParameter(PROPERTY_VALUE_SEARCH_TYPE);
        String multiFieldNodeName = request.getParameter(MULTI_FIELD_NODE_NAME);

        if (rootPagePath == null || rootPagePath.isEmpty()) {
            response.sendError(SlingHttpServletResponse.SC_BAD_REQUEST, "Root page path parameter is required.");
            return;
        }

        if (resourceType == null || resourceType.isEmpty()) {
            response.sendError(SlingHttpServletResponse.SC_BAD_REQUEST, "Resource type parameter is required.");
            return;
        }

        if (propertyName == null || propertyName.isEmpty()) {
            response.sendError(SlingHttpServletResponse.SC_BAD_REQUEST, "Property name parameter is required.");
            return;
        }

        PrintWriter out = getPrintWriter(response, resourceType, propertyName, existNotExist, propertyValue, valueSearchType);

        List<String> componentNodes = findComponentsByResourceTypeWithoutProperty(rootPagePath,
                resourceType, propertyName, propertyValue, existNotExist, valueSearchType, multiFieldNodeName, out);
        out.println("</table>");
        out.println("</br>");
        out.println("<h3> Total Results : " + componentNodes.size() + " </h3> ");
        out.close();
    }

    private static PrintWriter getPrintWriter(SlingHttpServletResponse response, String resourceType,
        String propertyName, String existNotExist, String propertyValue, String valueSearchType) throws IOException {
        response.setContentType(Constants.CT_TEXT_HTML);
        PrintWriter out = response.getWriter();
        out.println("<html><head><title>Response</title></head><body>");
        out.println("<h1>Search Results</h1>");
        out.println("<h3> Resource Type : " + resourceType + " </h3> ");
        out.println("<h3> Property Name : " + propertyName + " </h3> ");

        if (StringUtils.isNotEmpty(existNotExist)) {
            if (StringUtils.equalsIgnoreCase(existNotExist, "exist")) {
                out.println("<h3> Property Exists OR Not : Exists </h3> ");
            } else {
                out.println("<h3> Property Exists OR Not : Not Exists </h3> ");
            }
        }

        if (StringUtils.isNotEmpty(propertyValue)) {
            out.println("<h3> Property Value : " + propertyValue + " </h3> ");

            if (StringUtils.isNotEmpty(valueSearchType)) {
                out.println("<h3> Search Type : " + valueSearchType + " </h3> ");
            }
        }
        out.println("</br>");
        out.println("<table border='1' style='border-collapse: collapse;'>");
        out.println("<tr><th>No.</th><th>Page Name</th><th>Node Name</th><th>Node Path</th></tr>");
        return out;
    }

    private List<String> findComponentsByResourceTypeWithoutProperty(String rootPagePath, String resourceType,
        String propertyName, String propertyValue, String existNotExist, String valueSearchType, String multiFieldNodeName, PrintWriter out) {
        List<String> componentNodes = new ArrayList<>();
        ResourceResolver resourceResolver = practicePathUtilsService.getSystemUserResourceResolver();
        PageManager pageManager = resourceResolver.adaptTo(PageManager.class);

        try {
            Page rootPage = pageManager != null ? pageManager.getPage(rootPagePath) : null;
            if (rootPage != null) {
                Node rootPageNode = resourceResolver.getResource(rootPagePath).adaptTo(Node.class);
                if (null != rootPageNode) {
                    findComponentsRecursively(resourceResolver, rootPageNode, componentNodes,
                        resourceType, propertyName, propertyValue, existNotExist, valueSearchType,
                        multiFieldNodeName, out);
                }
            }
        } catch (RepositoryException e) {
            LOGGER.error("Error while searching for components: ", e);
        }

        return componentNodes;
    }

    private void findComponentsRecursively(ResourceResolver resolver, Node node, List<String> componentNodes, String resourceType,
       String propertyName, String propertyValue, String existNotExist, String valueSearchType,
       String multiFieldNodeName, PrintWriter out) throws RepositoryException {
        if (node.hasProperty(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY) &&
                node.getProperty(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY).getString().equals(resourceType)) {

            if (node.hasNode(multiFieldNodeName)) {
                Node itemRootNode = node.getNode(multiFieldNodeName);
                if (itemRootNode.hasNodes()) {
                    NodeIterator itemNodesItr = itemRootNode.getNodes();
                    while (itemNodesItr.hasNext()) {
                        Node itemNode = (Node) itemNodesItr.next();
                        boolean hasProperty = itemNode.hasProperty(propertyName);
                        validateConditions(resolver, itemNode, componentNodes, propertyName, propertyValue,
                            existNotExist, valueSearchType, out, hasProperty);
                    }
                }
            }
        }

        NodeIterator nodeIterator = node.getNodes();
        while (nodeIterator.hasNext()) {
            Node childNode = nodeIterator.nextNode();
            findComponentsRecursively(resolver, childNode, componentNodes, resourceType,
                propertyName, propertyValue, existNotExist, valueSearchType, multiFieldNodeName, out);
        }
    }

    private void validateConditions(ResourceResolver resolver, Node node, List<String> componentNodes,
        String propertyName, String propertyValue, String existNotExist, String valueSearchType,
        PrintWriter out, boolean hasProperty) throws RepositoryException {
        if (hasProperty && StringUtils.isNotEmpty(propertyValue)) {
                if (StringUtils.equalsIgnoreCase("contains", valueSearchType) &&
                    StringUtils.contains(node.getProperty(propertyName).getValue().getString(), propertyValue)) {
                    collectValuesInList(resolver, node, componentNodes, out);
                } else if (StringUtils.equalsIgnoreCase(node.getProperty(propertyName).getValue().getString(), propertyValue)) {
                    collectValuesInList(resolver, node, componentNodes, out);
                }
        } else if (StringUtils.isNotEmpty(existNotExist) && StringUtils.isEmpty(propertyValue)){
            if (existNotExist.equalsIgnoreCase("notExist") && !hasProperty ||
                    existNotExist.equalsIgnoreCase("exist") && hasProperty) {
                collectValuesInList(resolver, node, componentNodes, out);
            }
        }
    }

    private Page getPageFromNode(ResourceResolver resolver, Node node) throws RepositoryException {
        Resource pageResource = resolver.getResource(node.getPath());
        PageManager pageManager = resolver.adaptTo(PageManager.class);
        return pageManager != null ? pageManager.getContainingPage(pageResource) : null;
    }

    private void collectValuesInList(ResourceResolver resolver, Node node,
        List<String> componentNodes, PrintWriter out) throws RepositoryException {
        Page currentPage = getPageFromNode(resolver, node);
        String pageName = null != currentPage ? currentPage.getName() : StringUtils.EMPTY;
        out.println("<tr><td>" + (componentNodes.size() + 1) + "</td><td>" + pageName + "</td><td> " + node.getName() + "</td><td>" + node.getPath() + "</td></tr>");
        componentNodes.add(pageName + " - " + node.getName() + " - " + node.getPath());
    }
}

I hope you found out this article interesting and informative. Please share it with your friends to spread the knowledge.

You can follow me for upcoming blogs follow. Thank you!


메타데이터
post_id
0129e1a112fd
slug
aem-script-for-property-and-value-finder-based-on-resource-type-and-root-page-path-0129e1a112fd
url
https://medium.com/@toimrank/aem-script-for-property-and-value-finder-based-on-resource-type-and-root-page-path-0129e1a112fd
canonical_url
https://medium.com/@toimrank/aem-script-for-property-and-value-finder-based-on-resource-type-and-root-page-path-0129e1a112fd
author_url
https://medium.com/@toimrank
status
ok
fetched_at
2026-07-19 19:27:23