Getting hook_menu() to respond to a URN I have a site that can respond to URNs.  For example, I need to be able to serve up a response to

http://example.com/urn:myscheme:foo:bar:12345


So, I need a router item that can match against the "urn" or "urn:myscheme" portion, and get "foo:bar:12345" as the argument (either exploded or not).

Can hook_menu() be configured this way?

I have tried

$item['urn'] = array(...);
$item['urn:'] = array(...);


without any luck.  I can do this with a hook_url_inbound_alter() trick, but am curious whether it can be done directly.  For the purposes of this question, I can't use path aliases.
Would love to be proven wrong, but I don't think that's easily possible using hook_menu().

Core only considers / as a separator, and matches on string, so urn:, urn:myscheme and urn:myscheme:foo:bar:12345 can only be represented as completely different paths.

The guts of it happens in menu_get_item():

$original_map = arg(NULL, $path);

$parts = array_slice($original_map, 0, MENU_MAX_PARTS);
$ancestors = menu_get_ancestors($parts);
$router_item = db_query_range('SELECT * FROM {menu_router} WHERE path IN (:ancestors) ORDER BY fit DESC', 0, 1, array(':ancestors' =&gt; $ancestors))-&gt;fetchAssoc();


The call to arg() splits the path by /, which is hardcoded:

$arguments[$path] = explode('/', $path);


When menu_get_ancestors() returns for a path like urn/myscheme, it has two elements in the array: 'urn' and 'myscheme'. The same call for urn:myscheme returns an array with a single element, 'urn:myscheme'.

Those ancestors are used directly in the query to match the path in menu_router, so for the path urn:myscheme, you'll get this query:

SELECT * FROM {menu_router} WHERE path IN ('urn:myscheme') ORDER BY fit DESC


Try the same thing with urn:myscheme:foo:bar:12345, and as far as Drupal's concerned, it's a separate path that has to be handled by a different router item, as the query will be:

SELECT * FROM {menu_router} WHERE path IN ('urn:myscheme:foo:bar:12345') ORDER BY fit DESC


Without resorting to replacing menu.inc (which I think is pluggable if I remember rightly), hook_url_inbound_alter() will probably be the best best.