Powered by Zoomin Software. For more details please contactZoomin

Secure MarkLogic Server

XQuery - Matching by Paths or Attributes

  • Last Updated: April 14, 2026
  • 3 minute read
    • MarkLogic Server
    • Version 11.0
    • Documentation

This next example shows how protected paths can be used with fn:contains() and fn:matches(). The example uses the same roles from the previous example, adding a new role (els-role-3).

First unprotect the protected paths from the previous example:

(: unprotect the protected paths -> run against the Security database :)

xquery version "1.0-ml"; 
import module namespace sec = "http://marklogic.com/xdmp/security" 
  at "/MarkLogic/security.xqy";
      
sec:unprotect-path("secret", ()),
sec:unprotect-path("top-secret", ())

Note: Adding or unprotecting protected paths will trigger reindexing. After unprotecting elements, you must wait for reindexing to finish.

Create a new role els-role-3 and add els-user-3 to the role. See Create Roles and Create Users and Assign Roles for details.

Add a new document with permissions to the Documents database:

(: run this against the Documents database :)

xquery version "1.0-ml";

xdmp:document-insert(
"attributes.xml", <root>
 <title>Document Title</title>
 <summary>Summary of document contents</summary>
 <executive-summary>Executive summary of contents
  <info attr="EU">Only role with "EU" attribute can read this summary </info>
  <info attr="UK">Only role with "UK" attribute can read this summary </info>
  <info attr="US">Only role with "US" attribute can read this summary </info>
</executive-summary>
 <content>Contents of document 
  Unclassified content
  <notes> 
    <info attr="EU">Only role with "EU" attribute can read this content</info>
    <info attr="UK">Only role with "UK" attribute can read this content</info>
    <info attr="US">Only role with "US" attribute can read this content</info>
  </notes>
 </content>
</root>,
(xdmp:permission("els-role-1", "read"), xdmp:permission("els-role-2", "read"), xdmp:permission("els-role-3", "read"),
xdmp:permission("els-role-1", "update"), xdmp:permission("els-role-2", "update"), xdmp:permission("els-role-3", "update")))

Add the new protected paths with permissions for roles to the Security database:

(: add new protected paths -> run against the Security database :)

xquery version "1.0-ml";
import module namespace sec="http://marklogic.com/xdmp/security" 
  at "/MarkLogic/security.xqy";

sec:protect-path("//info[fn:matches(@attr, 'US')]", (), (xdmp:permission("els-role-1", "read"))),
sec:protect-path("//info[fn:matches(@attr, 'UK')]", (), (xdmp:permission("els-role-2", "read"), 
  xdmp:permission("els-role-3", "read"))),
sec:protect-path("//info[fn:matches(@attr, 'EU')]", (), (xdmp:permission("els-role-3", "read")))
=>
Returns three numbers representing the protected paths

Note: Adding, unprotecting, or changing permissions on protected paths will trigger reindexing.

Notice that the protected paths include attributes in the document elements. Also note that els-role-3 has permissions for two protected paths (@attr, ‘UK’ and @attr, ‘EU’).

Run this next query, similar to the previous queries, this time looking for the attributes.xml document. First query in the context of els-user-1 who has a role that can see the “US” attribute:

(: run this against the Documents database :)

xdmp:eval('fn:doc("attributes.xml")',(),
  <options xmlns="xdmp:eval">
    <user-id>{xdmp:user("els-user-1")}</user-id>
  </options>
)

=>
<?xml  version="1.0" encoding="UTF-8"?>
<root>
 <title>Document Title</title>
 <summary>Summary of document contents</summary>
 <executive-summary>Executive summary of contents 
  <info attr="US">Only role having "US" attribute can read this summary</info>
 </executive-summary>
 <content>Contents of document 
  Unclassified content 
 <notes>
  <info attr="US">Only role having "US" attribute can read this content
  </info>
 </notes>
 </content>
</root>

Next modify the query to run in the context of els-user-2, who has a role that can see the “UK” attribute:

(: run this against the Documents database :)

xdmp:eval('fn:doc("attributes.xml")',(),
  <options xmlns="xdmp:eval">
    <user-id>{xdmp:user("els-user-2")}</user-id>
  </options>
)

=>
<?xml  version="1.0" encoding="UTF-8"?>
<root>
 <title>Document Title</title>
 <summary>Summary of document contents</summary>
 <executive-summary>Executive summary of contents 
  <info attr="UK">Only role having "UK" attribute can read this summary
  </info>
 </executive-summary>
 <content>Contents of document 
  Unclassified content 
 <notes>
  <info attr="UK">Only role having "UK" attribute can read this content</info>
 </notes>
 </content>
</root>

And finally modify the query to run in the context of els-user-3:

(: run this against the Documents database :)

xdmp:eval('fn:doc("attributes.xml")',(),
  <options xmlns="xdmp:eval">
    <user-id>{xdmp:user("els-user-3")}</user-id>
  </options>
)

=>
<?xml  version="1.0" encoding="UTF-8"?>
<root>
 <title>Document Title</title>
 <summary>Summary of document contents</summary>
 <executive-summary>Executive summary of contents 
  <info attr="EU">Only role having "EU" attribute can read this summary

  </info>
  <info attr="UK">Only role having "UK" attribute can read this summary
   
  </info>
 </executive-summary>
 <content>Contents of document 
  Unclassified content
  
 <notes>
  <info attr="EU">Only role having "EU" attribute can read this content
     
  </info>
  <info attr="UK">Only role having "UK" attribute can read this content
     
  </info>
 </notes>
 </content>
</root>

The els-user-3 has protected path permissions on both elements with the “EU” info attribute and the elements with the “UK” info attribute, so the els-user-3 can see both elements. If you are getting different results, check to be sure that you created an els-role-3 and added the els-user-3 to that role.

Note: If you run the query in the context of the admin user, you will be able to see the entire document because the query is using fn:doc.

TitleResults for “How to create a CRG?”Also Available inAlert