On Mon, 10 Feb 2003, Baltz, Kenneth wrote:
> Date: Mon, 10 Feb 2003 15:04:48 -0800
> From: "Baltz, Kenneth" <[EMAIL PROTECTED]>
> Reply-To: Jakarta Commons Users List <[EMAIL PROTECTED]>
> To: Jakarta Commons Users List <[EMAIL PROTECTED]>
> Subject: [Digester]How do you populate a map?
>
> I'm really embarrassed after posting a HowTo on populating a map, but I've
> found that it's not as clear as I thought it was. I know how to do it with
> the following example:
>
> <?xml version='1.0'?>
> <map>
> <key name='The key'/>
> <value name='The value'/>
> </map>
>
> But how to do it with this?
>
> <?xml version='1.0'?>
> <map>
> <key name='KeyA'/>
> <value name='ValueA'/>
> <key name='KeyB'/>
> <value name='ValueB'/>
> </map>
>
My understanding of XML style guidelines is that the above is considered
poor form if you really want each key-value pair to be related to each
other. The recommended pattern would be something like this instead:
<?xml version='1.0'?>
<map>
<entry>
<key name='KeyA'/>
<value name='ValueA'/>
</entry>
<entry>
<key name='KeyB'/>
<value name='ValueB'/>
</entry>
</map>
where the relationship becomes obvious in the XML structure, *and* you can
easily use Digester's CallMethod rule to fire at the end of each <entry>,
with the parameter values coming from the nested <key> and <value>
elements:
digester.addObjectCreate("map", "java.util.HashMap");
digester.addCallMethod("map/entry",
"put", 2,
new String[] { "java.lang.Object",
"java.lang.Object" });
digester.addCallParam("map/entry/key", 0, "name");
digester.addCallParam("map/entry/value", 1, "name");
If the <key> and <value> elements were modified to take their input from
the element body:
<?xml version='1.0'?>
<map>
<entry>
<key>KeyA</key>
<value>ValueA'</value>
</entry>
<entry>
<key>KeyB</key>
<value>ValueB</value>
</entry>
</map>
then the latter two rules would become a little simpler:
digester.addObjectCreate("map", "java.util.HashMap");
digester.addCallMethod("map/entry",
"put", 2,
new String[] { "java.lang.Object",
"java.lang.Object" });
digester.addCallParam("map/entry/key", 0);
digester.addCallParam("map/entry/value", 1);
but this change in your XML document structure is not as important as
nesting the things that go together.
> CallMethodRule is only invoked at the end of <map>, so you can't call it
> twice, once for each key, value pair.
> The situation I have that I actually need to solve looks more like this:
>
> <Library>
> <Book title="The Firm" />
> <Book title="The Cat in the Hat" />
> </Library>
>
> I would want Library to be a HashMap with titles for keys and Book objects
> for values. You can't use a CallMethodRule on Book because the put() method
> belongs to Library, not Book.
I assume <Book> should create some sort of Book object, and you ultimately
want to call map.put(book.getTitle(), book), right? If so, it sounds like
time to write your own custom Rule implementation -- easy and fun! :-)
digester.addObjectCreate("Library", "java.util.Map");
digester.addObjectCreate("Library/Book", "com.mycompany.MyBook");
digester.addSetProperties("Library/Book"); // Sets "title" and others
digester.addRule("Library/Book",
new AddBookRule());
with an AddBookRule class:
public class AddBookRule extends Rule {
public void end() throws Exception {
MyBook book = (MyBook) digster.peek(0); // Top of stack
Map library = (Map) digester.peek(1); // Next-to-top of stack
library.put(book.getTitle(), book);
}
}
Alternatively, if MyLibrary were a simple class like this:
public class MyLibrary {
private Map books = new HashMap();
public void addBook(MyBook book) {
books.put(book.getTitle(), book);
}
public Map getBooks() {
return (books);
}
}
Then you could do without a custom Rule implementation:
digester.addObjectCreate("Library", "com.mycompany.MyLibrary");
digester.addObjectCreate("Library/Book", "com.mycompany.MyBook");
digester.addSetProperties("Library/Book"); // Sets "title" and others
digester.addSetNext("Library/Book",
"addBook", "com.mycompany.MyBook");
It's just a matter of where you want to add a little complexity.
>
> Help?
>
> BTW, I realize you can do this by creating proxy objects that call put() for
> you. That's inelegant IMHO and I was hoping that Digester 1.4 had solved
> this issue.
Digester 1.0 actually solved that issue -- that's why it is very easy to
create your own Rule implementations :-).
>
> K.C.
>
Craig
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]