tags:

views:

251

answers:

2

I'm using dom4j's rules api to fire an action if the predefined pattern //authorize matches an element in the following xml snippet.

     <authorize role_required="admin">
  <node title="node which is visible only to admin" path="" >
   <authorize role_required="admin">
    <node title="node which is visible only to admin" path=""/>
   </authorize>
   <authorize role_required="admin">
    <node title="node which is visible only to admin" path="">
     <authorize role_required="admin">
     </authorize>
      <node title="node which is visible only to admin" path=""/>
    </node>
   </authorize>
  </node>
 </authorize>
 <authorize role_deny="admin">
  <node title="Node which is not visible to admin" path=""/>
 </authorize>

Unfortunately it seems that it doesn't work with nested elements, only the authorize elements on the first level are found. The action is triggered only two times, but there are 5 authorize elements. Does anybody have an idea how to solve this problem? Thanks in advance.

I've tried to match the authorize tag with the following rule:

 Rule authorizationRule = new Rule();
 authorizationRule.setPattern( DocumentHelper.createPattern( "//authorize" ) );
 authorizationRule.setAction( new AuthorizationRule() );

this.stylesheet = new Stylesheet();

this.stylesheet.addRule(authorizationRule);
this.stylesheet.run(document);

The rule matches two times on the elements on the fist level. I cross checked the XPath pattern with the document.selectNodes method and got all five elements.

+2  A: 

Do your rules have this line?

stylesheet.applyTemplates(node);

Remember that your rules control descent into deeper elements.

It seems that patterns are not used for selecting elements, but for checking that element matches when going through the tree. If element matches the pattern, your action is called, but it's your responsibility to continue in child elements. If you don't, child elements are skipped.

(Disclaimer: My understanding may be wrong, I don't use dom4j, and just looked at cookbook).

Peter Štibraný
I was just testing this with dom4j (and wondering how the stylesheets and rules are supposed to work in it), and it seems you got it exactly right!
Jonik
+1  A: 

I think Peter nailed the issue; I'm just building on top of his answer.

This line in the code example by Thomas was a little confusing:

 authorizationRule.setAction( new AuthorizationRule() );

... unless AuthorizationRule is a custom implementation of Action, because that's what setAction takes.

Anyway, with the following code the action's run method indeed gets called for each five "authorize" elements:

Rule authorizationRule = new Rule();
authorizationRule.setPattern(DocumentHelper.createPattern("//authorize"));

final Stylesheet stylesheet = new Stylesheet();                                 
authorizationRule.setAction(new Action(){
    public void run(Node node) throws Exception {
       stylesheet.applyTemplates(node);
    }
 });

stylesheet.addRule(authorizationRule);
stylesheet.run(document);

(Only works after changing the XML snippet to well-formed document.)

The way you need to use the stylesheet inside the action seems a little awkward, and I'm not sure how this kind of thing is supposed to be done in dom4j. It's a shame that relevant classes like Stylesheet and Rule seem to be rather inadequately documented. (Consider e.g. the method run(Node node, String mode) whose mode parameter seems to lack explanation entirely.)

Jonik