commons-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Simon Kitching <>
Subject Re: Strange behaviour with xmlrules
Date Wed, 18 Jun 2003 22:24:26 GMT
Hi Lutz,

If I understand your mail, you have got a working solution, but are just
wondering why you need to put the "setNext" rule *before* the
"setContent" in order to get the setContent() method called before the
addBaz() method.

This is actually a side-effect of the core digester design. It is not a
"bug", despite the somewhat non-intuitive behaviour, and this behaviour
cannot be changed without radical changes to the Digester design.

In most cases it doesn't matter. Only if the method invoked by setNext
requires a fully initialized object does this behaviour cause a problem;
I presume that your setBaz method does?

The root cause of this kind of behaviour is that digester is a
stack-based system, and rules actually fire in 3 steps:
* The rule's "begin" method is invoked when the start tag is
encountered. this step may push stuff onto the object or parameter
* the rule's "body" method is invoked.
* the rule's "end" method is invoked when the end tag is encountered.
this rule is responsible for cleaning up any stack changes performed by
the begin method, restoring the digester object & paramter stacks to the
state they had before the rule fired.

In order to ensure proper stack-based behaviour, when multiple rules
match a pattern:
* their begin methods are called in the order the rules were added
* their body methods are called in the order the rules were added
* their end methods are called *in reverse order*.

It is because setNextRule and callMethodRule do their work in their
"end" methods (for good reasons) that they appear to fire in reverse



On Thu, 2003-06-19 at 01:41, Horn, Lutz wrote:
> Hi all,
> I've got problems understanding the behaviour of a certain
> case of xmlrules.
> I want to digest a XML file with the following structure:
> <foo>
>   <bar>
>     <baz>interesting content here</baz>
>   </bar>
>   <bar>
>     <baz>some more content I want</baz>
>   </bar>
> </foo>
> >From this I want to:
> 0. Creat a MyFoo container,
> 1. get all foo/bar/baz elements,
> 2. create a MyBaz bean for each such element,
> 3. fill it's field "content" from the character content of the the element
>    using the bean's setContent() method,
> 4. and store the bean in the MyFoo instance using a method called addBaz().
> The digester rules XML file I use is:
> ...
> <digester-rules>
>   <object-create-rule pattern="foo" classname="MyFoo"/>
>   <pattern value="foo/bar/baz">
>     <object-create-rule classname="MyBaz"/>
>     <call-method-rule methodname="setContent" paramcount="0"/>
>     <set-next-method methodname="addBaz"/>
>   </pattern>
> </digester-rules>
> Unfortunatley this doesn't work. What happens is that 
> 0. The MyFoo container is created,
> 1. a foo/bar/baz element is encountered and
> 2. a new MyBaz instance is created which is
> 3. immediately added to MyFoo using the addBaz() method *after* which
> 4. the method setContent() of the MyBaz instance is called.
> This leads to MyFoo containing only MyBaz instances with the content
> field null.
> My solution so far is to swap the <call-method-rule> and the
> <set-next-rule> which results in the setContent() method of the MyBaz
> instance being called *before* the addBaz() method of MyFoo is called.
> Is this a bug or a feature or did I miss something?
> Thanks
> Lutz
> ---------------------------------------------------------------------
> To unsubscribe, e-mail:
> For additional commands, e-mail:

View raw message