Apache Digester XML roule to invoke a custom setter on a bean

661 views Asked by At

I am trying to parse a big XML file using Apache commons-digester3. I am interested in extract only certain data. The XML is quite complex and I would prefer not to build the whole structure but rather match the patterns I am interested in.

Say I have the following XML:

<?xml version="1.0"?>
<foo>
    <level1>
        <level2>
            <bar>the bar</bar>
        </level2>
    </level1>
</foo>

And I have the following domain object that I want to parse into:

package my.pkg;

public class Foo {
    private String bar;

    // Note the name of the setter is not "setBar" but rather "setTheBar"
    public void setTheBar(String bar) {
        this.bar = bar;
    }
}

And now I have the XML rules I am having problems to get them right:

<digester-rules>
    <pattern value="foo">
        <object-create-rule classname="my.pkg.Foo"/>
        <pattern value="level1/level2/bar">
            <!--What do I need to pout on here the get "the bar" value injected into my Foo instance-->
        </pattern>
    </pattern>
</digester-rules>

I tried all sorts of combinations of set-method-rule, bean-property-setter-rule, etc but all failed to give me what I wanted. What I want seems so basic I am sure the solution must be so obvious but I cannot get it.

Thank you in advance for your help.

1

There are 1 answers

3
Barney On BEST ANSWER

I think a call-method-rule with "usingElementBodyAsArgument='true'" should work for you:

<digester-rules>
  <pattern value='foo'>
  <object-create-rule classname='my.pkg.Foo'/>
    <pattern value='level1/level2/bar'>
      <call-method-rule methodname='setTheBar'
                        usingElementBodyAsArgument='true'/>
    </pattern>
  </pattern>
</digester-rules>

However, I'd always note that XML rules are fairly limited - they can do all the basic stuff but miss quite a lot of more advanced functionality (custom rules etc.), and if you use digester regularly you may well find yourself moving from XML rules to programmatic rules at some point. Personally, I always use the programmatic rules now, as I know I can always do everything I need.

The programmatic equivalent of the XML rules above would be:

RulesModule rules = new AbstractRulesModule() {
  @Override
  public void configure() {
    forPattern("foo")
        .createObject().ofType(Foo.class);
    forPattern("foo/level1/level2/bar")
        .callMethod("setTheBar")
        .withParamCount(1)
        .usingElementBodyAsArgument();
  }
};

DigesterLoader loader = DigesterLoader.newLoader(rules);
Digester digester = loader.newDigester();

Foo foo = (Foo)digester.parse(...);

Hope this helps.