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]

Reply via email to