Hi,

Attached is a rule which behaves like a cross between SetPropertiesRule
and BeanPropertySetterRule-with-trailing-wildcard-match.

<point>
  <x>7</x>
  <y>8</y>
</point>

digester.addRule("point", new SetNestedPropertiesRule());

Note that the rule doesn't need to use ExtendedBaseRules with trailing
wildcard (which is very powerful but not very efficient). It is
configured with the pattern matching the "parent" element.

The implementation uses a trick developed for the plugins module:
inserting a "decorator" Rules object that performs custom matching to
detect the direct child elements.

Yes, this functionality can already be achieved with Digester, but this
is pretty efficient and convenient, and this configuration pattern is a
common one.


Opinions??

Regards,

Simon
/*
 * $Header: $
 * $Revision: $
 * $Date: $
 *
 * ====================================================================
 * 
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgement:  
 *       "This product includes software developed by the 
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgement may appear in the software itself,
 *    if and wherever such third-party acknowledgements normally appear.
 *
 * 4. The names "Apache", "The Jakarta Project", "Commons", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written 
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache",
 *    "Apache" nor may "Apache" appear in their names without prior 
 *    written permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 */ 


package org.apache.commons.digester;


import java.util.List;
import java.util.LinkedList;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.HashMap;
import java.beans.PropertyDescriptor;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.beanutils.DynaProperty;
import org.apache.commons.beanutils.PropertyUtils;

import org.xml.sax.Attributes;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


/**
 * <p>Rule implementation that sets properties on the object at the top of the
 * stack, based on child elements with names matching properties on that 
 * object.</p>
 *
 * <p>Example input that can be processed by this rule:</p>
 * <pre>
 * [point]
 *  [x]7[/x]
 *  [y]9[/y]
 * [/point]
 * </pre>
 *
 * <p>This rule supports custom mapping of attribute names to property names.
 * The default mapping for particular attributes can be overridden by using 
 * [EMAIL PROTECTED] #SetNestedPropertiesRule(String[] elementNames,
 *                                 String[] propertyNames)}.
 * This allows child elements to be mapped to properties with different names.
 * Certain elements can also be marked to be ignored.</p>
 *
 * <p>
 * A very similar effect can be achieved using a combination of the 
 * BeanPropertySetterRule and the ExtendedBaseRules rules manager; this
 * Rule, however, works fine with the default RulesBase rules manager.</p>
 *
 * @author Simon Kitching
 * @version $Revision: $ $Date: $
 */

public class SetNestedPropertiesRule extends Rule {

    private static final String PROP_IGNORE = "ignore-me";
    
    private Log log = null;
    
    private AnyChildRule anyChildRule = new AnyChildRule();
    private AnyChildRules newRules = new AnyChildRules(anyChildRule);
    private Rules oldRules = null;

    private boolean trimData = true;
    private boolean allowUnknownChildElements = false;
    
    private HashMap elementNames = new HashMap();

    // ----------------------------------------------------------- Constructors


    /**
     * Default constructor sets only the the associated Digester.
     *
     * @param digester The digester with which this rule is associated
     *
     * @deprecated The digester instance is now set in the 
     * [EMAIL PROTECTED] Digester#addRule} method.
     * Use [EMAIL PROTECTED] #SetNestedPropertiesRule} instead.
     */
    public SetNestedPropertiesRule(Digester digester) {
        this();
    }
    

    /**
     * Base constructor.
     */
    public SetNestedPropertiesRule() {
        // nothing to set up 
    }
    
    /** 
     * <p>Convenience constructor overrides the mapping for just one property.</p>
     *
     * <p>For details about how this works, see
     * [EMAIL PROTECTED] #SetNestedPropertiesRule(String[] elementNames, 
     * String[] propertyNames)}.</p>
     *
     * @param elementName map the child element to match 
     * @param propertyName to a property with this name
     */
    public SetNestedPropertiesRule(String elementName, String propertyName) {
        elementNames.put(elementName, propertyName);
    }
    
    /** 
     * <p>Constructor allows element->property mapping to be overriden.</p>
     *
     * <p>Two arrays are passed in. 
     * One contains the element names and the other the property names.
     * The element name / property name pairs are match by position
     * In order words, the first string in the element name list matches
     * to the first string in the property name list and so on.</p>
     *
     * <p>If a property name is null or the element name has no matching
     * property name, then this indicates that the element should be ignored.</p>
     * 
     * <h5>Example One</h5>
     * <p> The following constructs a rule that maps the <code>alt-city</code>
     * element to the <code>city</code> property and the <code>alt-state</code>
     * to the <code>state</code> property. 
     * All other child elements are mapped as usual using exact name matching.
     * <code><pre>
     *      SetNestedPropertiesRule(
     *                new String[] {"alt-city", "alt-state"}, 
     *                new String[] {"city", "state"});
     * </pre></code>
     *
     * <h5>Example Two</h5>
     * <p> The following constructs a rule that maps the <code>class</code>
     * element to the <code>className</code> property.
     * The element <code>ignore-me</code> is not mapped.
     * All other elements are mapped as usual using exact name matching.
     * <code><pre>
     *      SetPropertiesRule(
     *                new String[] {"class", "ignore-me"}, 
     *                new String[] {"className"});
     * </pre></code>
     *
     * @param elementNames names of elements to map
     * @param propertyNames names of properties mapped to
     */
    public SetNestedPropertiesRule(String[] elementNames, String[] propertyNames) {
        for (int i=0, size=elementNames.length; i<size; i++) {
            String propName = null;
            if (i < propertyNames.length) {
                propName = propertyNames[i];
            }
            
            if (propName == null) {
                this.elementNames.put(elementNames[i], PROP_IGNORE);
            }
            else {
                this.elementNames.put(elementNames[i], propName);
            }
        }
    }
        
    // --------------------------------------------------------- Public Methods


    public void setDigester(Digester digester) {
        super.setDigester(digester);
        log = digester.getLogger();
        anyChildRule.setDigester(digester);
    }
    
    /**
     * When set to true, any text within child elements will have leading
     * and trailing whitespace removed before assignment to the target
     * object. The default value for this attribute is true.
     */
    public void setTrimData(boolean trimData) {
        this.trimData = trimData;
    }
    
    /** See [EMAIL PROTECTED] #setTrimData}. */
     public boolean getTrimData() {
        return trimData;
    }
    
    /**
     * When set to true, any child element for which there is no
     * corresponding object property will cause an error to be reported.
     * The default value of this attribute is false (not allowed).
     */
    public void setAllowUnknownChildElements(boolean allowUnknownChildElements) {
        this.allowUnknownChildElements = allowUnknownChildElements;
    }
    
    /** See [EMAIL PROTECTED] #setAllowUnknownChildElements}. */
     public boolean getAllowUnknownChildElements() {
        return allowUnknownChildElements;
    }
    
    /**
     * Process the beginning of this element.
     *
     * @param namespace is the namespace this attribute is in, or null
     * @param name is the name of the current xml element
     * @param attributes is the attribute list of this element
     */
    public void begin(String namespace, String name, Attributes attributes) 
                      throws Exception {
        oldRules = digester.getRules();
        newRules.init(digester.getMatch()+"/", oldRules);
        digester.setRules(newRules);
    }
    
    /**
     * This is only invoked after all child elements have been processed,
     * so we can remove the custom Rules object that does the 
     * child-element-matching.
     */
    public void body(String bodyText) throws Exception {
        digester.setRules(oldRules);
    }

    /**
     * <p>Add an additional element name to property name mapping.
     * This is intended to be used from the xml rules.
     */
    public void addAlias(String elementName, String propertyName) {
        if (propertyName == null) {
            elementNames.put(elementName, PROP_IGNORE);
        }
        else {
            elementNames.put(elementName, propertyName);
        }
    }
  
    /**
     * Render a printable version of this Rule.
     */
    public String toString() {

        StringBuffer sb = new StringBuffer("SetNestedPropertiesRule[");
        sb.append("]");
        return (sb.toString());
    }

    //----------------------------------------- local classes 

    private class AnyChildRules implements Rules {
        private String matchPrefix = null;
        private Rules decoratedRules = null;
        
        private ArrayList rules = new ArrayList(1);
        private AnyChildRule rule;
        
        public AnyChildRules(AnyChildRule rule) {
            this.rule = rule;
            rules.add(rule); 
        }
        
        public Digester getDigester() { return null; }
        public void setDigester(Digester digester) {}
        public String getNamespaceURI() {return null;}
        public void setNamespaceURI(String namespaceURI) {}
        public void add(String pattern, Rule rule) {}
        public void clear() {}
        
        public List match(String matchPath) { 
            return match(null,matchPath); 
        }
        
        public List match(String namespaceURI, String matchPath) {
            List match = decoratedRules.match(namespaceURI, matchPath);
            
            if ((matchPath.startsWith(matchPrefix)) &&
                (matchPath.indexOf('/', matchPrefix.length()) == -1)) {
                    
                // The current element is a direct child of the element
                // specified in the init method, so include it as the
                // first rule in the matches list. The way that
                // SetNestedPropertiesRule is used, it is in fact very
                // likely to be the only match, so we optimise that
                // solution by keeping a list with only the AnyChildRule
                // instance in it.
                
                if ((match == null || match.size()==0)) {
                    return rules;
                }
                else {
                    // it might not be safe to modify the returned list,
                    // so clone it first.
                    LinkedList newMatch = new LinkedList(match);
                    //newMatch.addFirst(rule);
                    newMatch.addLast(rule);
                    return newMatch;
                }
            }            
            else {
                return match;
            }
        }
        
        public List rules() {
            // This is not actually expected to be called.
            throw new RuntimeException(
                "AnyChildRules.rules not implemented.");
        }
        
        public void init(String prefix, Rules rules) {
            matchPrefix = prefix;
            decoratedRules = rules;
        }
    }
    
    private class AnyChildRule extends Rule {
        private String currChildNamespaceURI = null;
        private String currChildElementName = null;
        
        public void begin(String namespaceURI, String name, 
                              Attributes attributes) throws Exception {
    
            currChildNamespaceURI = namespaceURI;
            currChildElementName = name;
        }
        
        public void body(String value) throws Exception {
            boolean debug = log.isDebugEnabled();

            String propName = (String) elementNames.get(currChildElementName);
            if (propName == PROP_IGNORE) {
                // note: above deliberately tests for IDENTITY, not EQUALITY
                return;
            }
            if (propName == null) {
                propName = currChildElementName;
            }
    
            if (digester.log.isDebugEnabled()) {
                digester.log.debug("[SetNestedPropertiesRule]{" + digester.match +
                        "} Setting property '" + propName + "' to '" +
                        value + "'");
            }
    
            // Populate the corresponding properties of the top object
            Object top = digester.peek();
            if (digester.log.isDebugEnabled()) {
                if (top != null) {
                    digester.log.debug("[SetNestedPropertiesRule]{" + digester.match +
                                       "} Set " + top.getClass().getName() +
                                       " properties");
                } else {
                    digester.log.debug("[SetPropertiesRule]{" + digester.match +
                                       "} Set NULL properties");
                }
            }
 
            if (trimData) {
                value = value.trim();
            }

            if (!allowUnknownChildElements) {
                // Force an exception if the property does not exist
                // (BeanUtils.setProperty() silently returns in this case)
                if (top instanceof DynaBean) {
                    DynaProperty desc =
                        ((DynaBean) top).getDynaClass().getDynaProperty(propName);
                    if (desc == null) {
                        throw new NoSuchMethodException
                            ("Bean has no property named " + propName);
                    }
                } else /* this is a standard JavaBean */ {
                    PropertyDescriptor desc =
                        PropertyUtils.getPropertyDescriptor(top, propName);
                    if (desc == null) {
                        throw new NoSuchMethodException
                            ("Bean has no property named " + propName);
                    }
                }
            }
            
            BeanUtils.setProperty(top, propName, value);
        }
    
        public void end(String namespace, String name) throws Exception {
            currChildElementName = null;
        }
    }
}
/*
 * $Header:  $
 * $Revision: $
 * $Date: $
 *
 * ====================================================================
 * 
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgement:  
 *       "This product includes software developed by the 
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgement may appear in the software itself,
 *    if and wherever such third-party acknowledgements normally appear.
 *
 * 4. The names "Apache", "The Jakarta Project", "Commons", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written 
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache",
 *    "Apache" nor may "Apache" appear in their names without prior 
 *    written permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 */ 


package org.apache.commons.digester;


import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

import org.xml.sax.SAXException;


/**
 * <p> Test case for <code>SetNestedPropertiesRule</code>.
 * This contains tests for the main applications of the rule
 * and two more general tests of digester functionality used by this rule.
 */
public class SetNestedPropertiesRuleTestCase extends TestCase {


    // ----------------------------------------------------- Instance Variables

    /**
     * Simple test xml document used in the tests.
     */
    protected final static String TEST_XML =
        "<?xml version='1.0'?>" +
        "<root>ROOT BODY" +
        "<alpha>ALPHA BODY</alpha>" +
        "<beta>BETA BODY</beta>" +
        "<gamma>GAMMA BODY</gamma>" +
        "<delta>DELTA BODY</delta>" +
        "</root>";


    /**
     * The digester instance we will be processing.
     */
    protected Digester digester = null;


    // ----------------------------------------------------------- Constructors


    /**
     * Construct a new instance of this test case.
     *
     * @param name Name of the test case
     */
    public SetNestedPropertiesRuleTestCase(String name) {

        super(name);

    }


    // --------------------------------------------------- Overall Test Methods


    /**
     * Set up instance variables required by this test case.
     */
    public void setUp() {

        digester = new Digester();

    }


    /**
     * Return the tests included in this test suite.
     */
    public static Test suite() {

        return (new TestSuite(SetNestedPropertiesRuleTestCase.class));

    }


    /**
     * Tear down instance variables required by this test case.
     */
    public void tearDown() {

        digester = null;

    }



    // ------------------------------------------------ Individual Test Methods


    /**
     * Test that you can successfully automatically set properties.
     */
    public void testAutomaticallySetProperties()
        throws SAXException, IOException {

        // going to be setting properties on a SimpleTestBean
        digester.addObjectCreate("root",
                                 "org.apache.commons.digester.SimpleTestBean");

        // match all children of root with this rule
        digester.addRule("root", new SetNestedPropertiesRule());

        SimpleTestBean bean = (SimpleTestBean) digester.parse(xmlTestReader());

        // check properties are set correctly
        assertEquals(
                "Property alpha not set correctly",
                "ALPHA BODY",
                bean.getAlpha());

        assertEquals(
                "Property beta not set correctly",
                "BETA BODY",
                bean.getBeta());

        assertEquals(
                "Property gamma not set correctly",
                "GAMMA BODY",
                bean.getGamma());


    }

    /**
     * Test that you can customise the property mappings.
     */
    public void testCustomisedProperties()
        throws SAXException, IOException {

        // going to be setting properties on a SimpleTestBean
        digester.addObjectCreate("root",
                                 "org.apache.commons.digester.SimpleTestBean");

        // ignorethe "alpha" element
        // map the "beta" element into the gamma property
        // map the gamma element into the delta property
        // ignore the delta element
        
        Rule rule = new SetNestedPropertiesRule(
            new String[]{"alpha", "beta", "gamma", "delta"},
            new String[]{null, "gamma", "delta"});
            
        digester.addRule("root", rule);

        SimpleTestBean bean = (SimpleTestBean) digester.parse(xmlTestReader());

        // check properties are set correctly
        assertEquals(
                "Property alpha not set correctly",
                null,
                bean.getAlpha());

        assertEquals(
                "Property beta not set correctly",
                null,
                bean.getBeta());

        assertEquals(
                "Property gamma not set correctly",
                "BETA BODY",
                bean.getGamma());

        assertEquals(
                "Property delta not set correctly",
                "GAMMA BODY",
                bean.getDeltaValue());
                
         // check no bad rules object is left
         assertEquals(
            "Digester rules object not reset.",
            RulesBase.class, digester.getRules().getClass());
    }


    /**
     * Test that:
     * <ul>
     * <li> you can have rules matching the same pattern as the 
     *  SetNestedPropertiesRule, </li>
     * <li> you can have rules matching child elements of the rule, </li>
     * <li> the Rules object is reset nicely. </li>
     * </ul>
     */
    public void testMultiRuleMatch()
        throws SAXException, IOException {

        String testXml =
            "<?xml version='1.0'?>" +
            "<root>" +
                "<testbean alpha='alpha-attr'>ROOT BODY" +
                    "<beta>BETA BODY</beta>" +
                    "<gamma>GAMMA " +
                    "<prop name='delta' value='delta-prop'/>" +
                    "BODY" +
                    "</gamma>" +
                "</testbean>" +
            "</root>";

        Reader reader = new StringReader(testXml);

        // going to be setting properties on a SimpleTestBean
        digester.addObjectCreate("root/testbean",
                                 "org.apache.commons.digester.SimpleTestBean");

        digester.addRule("root/testbean", new SetNestedPropertiesRule());
        digester.addSetProperties("root/testbean");
        digester.addSetProperty("root/testbean/gamma/prop", "name", "value");

        SimpleTestBean bean = (SimpleTestBean) digester.parse(reader);

        assertNotNull("No object created", bean);
        
        // check properties are set correctly
        assertEquals(
                "Property alpha not set correctly",
                "alpha-attr",
                bean.getAlpha());

        assertEquals(
                "Property beta not set correctly",
                "BETA BODY",
                bean.getBeta());

        assertEquals(
                "Property gamma not set correctly",
                "GAMMA BODY",
                bean.getGamma());

        assertEquals(
                "Property delta not set correctly",
                "delta-prop",
                bean.getDeltaValue());

         // check no bad rules object is left
         assertEquals(
            "Digester rules object not reset.",
            RulesBase.class, digester.getRules().getClass());
    }

    /**
     * Test that unknown child elements trigger an exception.
     */
    public void testUnknownChildrenCausesException()
        throws SAXException, IOException {

        String testXml =
            "<?xml version='1.0'?>" +
            "<root>" +
                "<testbean>" +
                    "<beta>BETA BODY</beta>" +
                    "<foo>GAMMA</foo>" +
                "</testbean>" +
            "</root>";

        Reader reader = new StringReader(testXml);

        // going to be setting properties on a SimpleTestBean
        digester.addObjectCreate("root",
                                 "org.apache.commons.digester.SimpleTestBean");

        Rule rule = new SetNestedPropertiesRule();
        digester.addRule("root", rule);

        try {
            SimpleTestBean bean = (SimpleTestBean) digester.parse(reader);
            fail("Expected to generate an exception.");
        } catch(SAXException e) {
            Exception nested = e.getException();
            if ((nested==null) || !(nested instanceof NoSuchMethodException)) {
                // nope, not the sort of exception we expected
                throw e;
            }
        }
    }

    /**
     * Test that unknown child elements are allowed if the appropriate
     * flag is set.
     */
    public void testUnknownChildrenExceptionOverride()
        throws SAXException, IOException {

        String testXml =
            "<?xml version='1.0'?>" +
            "<root>" +
                "<testbean>" +
                    "<beta>BETA BODY</beta>" +
                    "<foo>GAMMA</foo>" +
                "</testbean>" +
            "</root>";

        Reader reader = new StringReader(testXml);

        // going to be setting properties on a SimpleTestBean
        digester.addObjectCreate("root",
                                 "org.apache.commons.digester.SimpleTestBean");

        SetNestedPropertiesRule rule = new SetNestedPropertiesRule();
        rule.setAllowUnknownChildElements(true);
        digester.addRule("root", rule);

        SimpleTestBean bean = (SimpleTestBean) digester.parse(reader);
        assertNotNull(bean);
    }


    /**
     * Get input stream from [EMAIL PROTECTED] #TEST_XML}.
     */
    private Reader xmlTestReader() throws IOException {
        return new StringReader(TEST_XML);
    }

}



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to