Date: 2004-08-31T16:13:28 Editor: SimonKitching <[EMAIL PROTECTED]> Wiki: Jakarta Commons Wiki Page: Digester/FAQ URL: http://wiki.apache.org/jakarta-commons/Digester/FAQ
no comment Change Log: ------------------------------------------------------------------------------ @@ -72,6 +72,11 @@ and !RulesBase classes are not supposed to be modified by the parsing, ie are "stateless" with respect to the sax parsing stage and so are pretty safe to reuse. +You can also create a parser object and pass it to the digester constructor, to +save having to instantiate a new parser object when new Digester objects are +instantiated. You will of course need to call any necessary methods on the +parser to reset it before each parse. + === How do I enable debugging output for Digester? === Digester uses the commons-logging package. Commons-logging can be configured in @@ -87,3 +92,63 @@ the classpath. See http://logging.apache.org/log4j/docs for more information on log4j. For more options, see the commons-logging project documentation. + +=== How do I get CallMethodRule to fire before SetNextRule? === + +Often, when using !SetNextRule to add a newly created object to a parent object, it is necessary +to ensure that the child object's members are all fully initialised from the input xml before +calling the parent object's add method. However the intuitive approach does not work. + +Given these rules: +{{{ + digester.addObjectCreate("parent", Parent.class); + digester.addObjectCreate("parent/child", Child.class); + digester.addCallMethod("parent/child", "setName", 1); + digester.addCallParam("parent/child/name", 0); + digester.addSetNext("parent/child", "addChild"); +}}} +and the xml +{{{ + <parent> + <child> + <name="child1"/> + </child> + </parent> +}}} +the sequence of operations is: + * create Parent instance + * create Child instance + * call parent.addChild(child) + * call child.setName("child1") + +The reason is a side-effect of the stack-based nature of Digester. + +Rule objects can perform their work when the matching start tag is found, or when the +matching end tag is found. The !CallMethodRule has no choice: it has to fire when the +end tag is found, because it has to wait until all its parameters are available. And +!SetNextRule also performs its operations in the end method (ie at the end tag). + +However end methods for rules are fired in *reverse* order from the order they +are added to a digester instance, in order to ensure that if the rule manipulates +a stack then proper stack LIFO ordering is preserved. Because the !CallMethodRule +was added before the !SetNextRule, its begin method fires before the !SetNextRule +begin method but the !CallMethodRule end method (where the child object's setName +method is called) fires after the !SetNextRule end method (where the addChild +method is called). + +The solution is simple, though not entirely intuitive; put the !SetNextRule first, +resulting in its end method being called last. The following code results in the +child's name being fully set before the addChild method is called: +{{{ + digester.addObjectCreate("parent", Parent.class); + digester.addObjectCreate("parent/child", Child.class); + digester.addSetNext("parent/child", "addChild"); + digester.addCallMethod("parent/child", "setName", 1); + digester.addCallParam("parent/child/name", 0); +}}} + +Note that this problem does *not* occur when using the !SetPropertiesRule. This +rule does all its work when the matching start tag is encountered (because it +only requires the attributes which are all present on the start tag) and so does +not experience the "reverse call" order that applies to the "end" method of +Rules. --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
