Expand my Community achievements bar.

Adobe Summit 2025: AEM Session Recordings Are Live! Missed a session or want to revisit your favorites? Watch the latest recordings now.

AEM sitemap - request two sitemaps in the same Node

Avatar

Level 1

Hi team ,

 

I have a request to implement two different Sling sitemaps in the same page/node which will be the language page.

 

one will be for pages and the other for assets , the content is irrelevant but I’m looking for tips more on the option to invoke or schedule two different sitemaps in the same node like:

 

 

- com.mypackage.MyCustomSitemap1.java

- com.mypackage.MyCustomSitemap2.java 

 

and invoke the sitemap like :

 

en.sitemap.xml

en.sitemap2.xml 

 

I tried setting it up as a different selector extending from ResourceTreeSitemapGenerator and set a selector in here , also registering in the sitemap servlet configuration but it is not working , does anybody has any advice how to configure this scenario ? Is highly appreciate it.

 

 

 

 

7 Replies

Avatar

Community Advisor

Hi @neoz_zilon,

You can register multiple custom sitemap generators for the same page node (like a language root) in AEM using Sling Sitemap. Each one can be tied to a different selector, like sitemap.xml and sitemap-assets.xml. Here's how I usually approach it:

  1. Create separate generators
    Build two classes extending ResourceTreeSitemapGenerator:

    • One for pages (eg. MyCustomSitemap1.java)

    • One for assets (eg. MyCustomSitemap2.java)

  2. Register with unique names (selectors)
    Give each generator a unique name using the SitemapGenerator.NAME property. This controls the selector used in the URL.

    Eg.

    @Component(
        service = SitemapGenerator.class,
        property = {
            SitemapGenerator.NAME + "=pages" // becomes sitemap.xml
        }
    )
    public class MyCustomSitemap1 extends ResourceTreeSitemapGenerator {
        // logic for pages
    }
    
    @Component(
        service = SitemapGenerator.class,
        property = {
            SitemapGenerator.NAME + "=assets" // becomes sitemap-assets.xml
        }
    )
    public class MyCustomSitemap2 extends ResourceTreeSitemapGenerator {
        // logic for assets
    }
  3. Configure the Sitemap Servlet
    Make sure the sitemap servlet is set up to handle both selectors:

    {
      "sling.servlet.selectors": ["sitemap", "sitemap-assets"],
      "sling.servlet.extensions": "xml",
      "sling.servlet.resourceTypes": ["sling:Folder", "cq:Page"]
    }

    (Or use a factory config for org.apache.sling.sitemap.SitemapServlet.)

  4. Access the URLs
    Once everything is registered, you should be able to access:

    • /en.sitemap.xml --> page sitemap

    • /en.sitemap-assets.xml --> asset sitemap

    These selectors are customizable based on what you register.

References: https://github.com/apache/sling-org-apache-sling-sitemap

https://javadoc.io/doc/org.apache.sling/org.apache.sling.sitemap/latest/org/apache/sling/sitemap/spi...

https://www.tothenew.com/blog/exploring-apache-sling-sitemap-generator-with-customization-in-aem/

Hope that helps!

 


Santosh Sai

AEM BlogsLinkedIn


Avatar

Level 1

hi @SantoshSai 

 

Thanks for your reply! this is what I needed.

 

Just have one extra question, I'm unable to resolve the CONSTANT: SitemapGenerator.NAME and reviewed the source code as well for this one, and don't see the constant. Do you know if it is another class, or the value of this constant, to add it.

 

Really appreciate it. 

Avatar

Community Advisor

@neoz_zilon 

The constant SitemapGenerator.NAME is not defined in the Sling Sitemap API. That line is a common shorthand used in examples, but in actual implementation, you need to manually define the property key as a string.

Refer: 

@Component(
    service = SitemapGenerator.class,
    property = {
        "sling.sitemap.name=pages"  // this defines the selector as 'sitemap-pages.xml'
    }
)
public class MyCustomSitemap1 extends ResourceTreeSitemapGenerator {
    // implement logic for page sitemap
}

@Component(
    service = SitemapGenerator.class,
    property = {
        "sling.sitemap.name=assets"  // this defines the selector as 'sitemap-assets.xml'
    }
)
public class MyCustomSitemap2 extends ResourceTreeSitemapGenerator {
    // implement logic for asset sitemap
}

This maps to the selector used in the sitemap URL.

  • So /en.sitemap-pages.xml and /en.sitemap-assets.xml will be the result.


Santosh Sai

AEM BlogsLinkedIn


Avatar

Community Advisor

Hi @neoz_zilon ,

To create two separate sitemaps (e.g., one for pages and one for assets) under the same AEM node (like /en) using Apache Sling Sitemap in AEM, follow this implementation approach:


Step-by-Step Working Solution

1. Create Two Sitemap Generator Components

MyCustomPageSitemap.java

@Component(
    service = SitemapGenerator.class,
    property = {
        "sling.sitemap.name=pages" // becomes selector "sitemap-pages.xml"
    }
)
public class MyCustomPageSitemap extends ResourceTreeSitemapGenerator {
    // Optional: override methods to customize page sitemap logic
}

MyCustomAssetSitemap.java

@Component(
    service = SitemapGenerator.class,
    property = {
        "sling.sitemap.name=assets" // becomes selector "sitemap-assets.xml"
    }
)
public class MyCustomAssetSitemap extends ResourceTreeSitemapGenerator {
    // Optional: override methods to customize asset sitemap logic
}

Note: There's no constant like SitemapGenerator.NAME in the current Sling Sitemap API — use string literal: "sling.sitemap.name=your-selector"

2. Sitemap Servlet Configuration (IMPORTANT)

If you need to ensure the sitemap servlet can respond to both selectors:

org.apache.sling.sitemap.SitemapServlet.cfg.json (OSGi config file)

{
  "sling.servlet.selectors": [
    "sitemap-pages",
    "sitemap-assets"
  ],
  "sling.servlet.extensions": ["xml"],
  "sling.servlet.resourceTypes": [
    "cq:Page",
    "sling:Folder"
  ]
}

You can also create this config via the Web Console or in Code (OSGi Factory Config).

3. Deploy & Access

Assuming the language root is /content/site/en, these URLs will now work:

/content/site/en.sitemap-pages.xml

/content/site/en.sitemap-assets.xml

Verify below:

 - Both components use @Component(service = SitemapGenerator.class)
 - You’ve used unique selectors: sitemap-pages, sitemap-assets
- Your servlet is configured to recognize those selectors
- You’re requesting sitemaps from nodes of type cq:Page or sling:Folder
- The sitemap service is enabled for the site root in /conf (if using configuration-based setup)

Regards,
Amit

 

 

Avatar

Level 1

HI ,

 

Thanks for the detailed instructions, I tried this option but didn't work.

 

even turned debug logs nothing ... Only triggers doing the en.sitemap.xml 

 

but nothing for en.sitemap-pages.xml or en.sitemap-assets.xml

 

@Component(
service = SitemapGenerator.class,
property = {
"sling.sitemap.name=assets" // becomes selector "sitemap-assets.xml"
}
)

public class AssetsSitemapGenerator extends ResourceTreeSitemapGenerator {
@Component(
service = SitemapGenerator.class,
property = {
"sling.sitemap.name=pages" // becomes selector "sitemap-pages.xml"
}
)

public class PagesAndAssetsSitemapGenerator extends ResourceTreeSitemapGenerator {

 

Adobe_Experience_Manager_Web_Console_-_Configuration.png

 

 

 

 

 

 

Avatar

Level 2

@neoz_zilon I bet if he'll answer back - because his all answers are form AI tool.

Avatar

Level 1

None of the proposed solutions worked, not sure if anybody has tested this one, and it might be a reason why there are no examples about this one ... If anyone has any clues'll appreciate it, if I find the way to fix it, I'll share it.