[DIGESTER-105] Need to process [attribute id=name]somename[/attribute]

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/digester/trunk@1140140 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index 6337dab..644907c 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -91,6 +91,8 @@
 
  * [DIGESTER-90] xmlrules does not support setNamespaceURI
 
+ * [DIGESTER-105] Need to process [attribute id="name"]somename[/attribute]
+
  * [DIGESTER-127] Allow DigesterLoader to accept an instance of a preconfigured Digester
 
  * [DIGESTER-131] Allow recursive match in ExtendedBaseRules
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index ecaf2f9..2b07171 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -35,6 +35,9 @@
     <action dev="simonetripodi" type="fix" issue="DIGESTER-103">
       xmlrules does not support NodeCreateRule
     </action>
+    <action dev="simonetripodi" type="add" issue="DIGESTER-105">
+      Need to process [attribute id="name"]somename[/attribute]
+    </action>
     <action dev="simonetripodi" type="fix" issue="DIGESTER-118">
       ObjectCreateRule shouldn't keep className as a field.
     </action>
diff --git a/src/main/java/org/apache/commons/digester3/BeanPropertySetterRule.java b/src/main/java/org/apache/commons/digester3/BeanPropertySetterRule.java
index 557d9a1..d94a504 100644
--- a/src/main/java/org/apache/commons/digester3/BeanPropertySetterRule.java
+++ b/src/main/java/org/apache/commons/digester3/BeanPropertySetterRule.java
@@ -27,6 +27,7 @@
 import org.apache.commons.beanutils.DynaBean;
 import org.apache.commons.beanutils.DynaProperty;
 import org.apache.commons.beanutils.PropertyUtils;
+import org.xml.sax.Attributes;
 
 /**
  * <p>
@@ -70,7 +71,7 @@
      */
     public BeanPropertySetterRule()
     {
-        this( (String) null );
+        this( null );
     }
 
     // ----------------------------------------------------- Instance Variables
@@ -78,7 +79,12 @@
     /**
      * Set this property on the top object.
      */
-    private final String propertyName;
+    private String propertyName;
+
+    /**
+     * Extract the property name from attribute
+     */
+    private String propertyNameFromAttribute;
 
     /**
      * The body text used to set the property.
@@ -98,6 +104,17 @@
     }
 
     /**
+     * Sets the attribute name from which the property name has to be extracted.
+     *
+     * @param propertyNameFromAttribute the attribute name from which the property name has to be extracted.
+     * @since 3.0
+     */
+    public void setPropertyNameFromAttribute( String propertyNameFromAttribute )
+    {
+        this.propertyNameFromAttribute = propertyNameFromAttribute;
+    }
+
+    /**
      * Returns the body text used to set the property.
      *
      * @return The body text used to set the property
@@ -111,6 +128,22 @@
      * {@inheritDoc}
      */
     @Override
+    public void begin( String namespace, String name, Attributes attributes )
+        throws Exception
+    {
+        if ( propertyNameFromAttribute != null )
+        {
+            propertyName = attributes.getValue( propertyNameFromAttribute );
+
+            getDigester().getLogger().warn( format( "[BeanPropertySetterRule]{%s} Attribute '%s' not found in matching element '%s'",
+                                                    getDigester().getMatch(), propertyNameFromAttribute, name ) );
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
     public void body( String namespace, String name, String text )
         throws Exception
     {
diff --git a/src/main/java/org/apache/commons/digester3/binder/BeanPropertySetterBuilder.java b/src/main/java/org/apache/commons/digester3/binder/BeanPropertySetterBuilder.java
index 3a352aa..cbd654b 100644
--- a/src/main/java/org/apache/commons/digester3/binder/BeanPropertySetterBuilder.java
+++ b/src/main/java/org/apache/commons/digester3/binder/BeanPropertySetterBuilder.java
@@ -30,6 +30,8 @@
 
     private String propertyName;
 
+    private String attribute;
+
     BeanPropertySetterBuilder( String keyPattern, String namespaceURI, RulesBinder mainBinder,
                                LinkedRuleBuilder mainBuilder )
     {
@@ -49,12 +51,31 @@
     }
 
     /**
+     * Sets the attribute name from which the property name has to be extracted.
+     *
+     * @param propertyName The name of property to set
+     * @return this builder instance
+     */
+    public BeanPropertySetterBuilder extractPropertyNameFromAttribute( String attribute )
+    {
+        if ( attribute == null )
+        {
+            reportError( "setBeanProperty().extractPropertyNameFromAttribute( String )",
+                         "Attribute name can not be null" );
+        }
+        this.attribute = attribute;
+        return this;
+    }
+
+    /**
      * {@inheritDoc}
      */
     @Override
     protected BeanPropertySetterRule createRule()
     {
-        return new BeanPropertySetterRule( propertyName );
+        BeanPropertySetterRule rule = new BeanPropertySetterRule( propertyName );
+        rule.setPropertyNameFromAttribute( attribute );
+        return rule;
     }
 
 }
diff --git a/src/main/java/org/apache/commons/digester3/xmlrules/BeanPropertySetterRule.java b/src/main/java/org/apache/commons/digester3/xmlrules/BeanPropertySetterRule.java
index 9b93cca..c9266e8 100644
--- a/src/main/java/org/apache/commons/digester3/xmlrules/BeanPropertySetterRule.java
+++ b/src/main/java/org/apache/commons/digester3/xmlrules/BeanPropertySetterRule.java
@@ -19,6 +19,7 @@
  * under the License.
  */
 
+import org.apache.commons.digester3.binder.BeanPropertySetterBuilder;
 import org.apache.commons.digester3.binder.LinkedRuleBuilder;
 import org.apache.commons.digester3.binder.RulesBinder;
 import org.xml.sax.Attributes;
@@ -42,7 +43,14 @@
     protected void bindRule( LinkedRuleBuilder linkedRuleBuilder, Attributes attributes )
         throws Exception
     {
-        linkedRuleBuilder.setBeanProperty().withName( attributes.getValue( "propertyname" ) );
+        BeanPropertySetterBuilder builder =
+            linkedRuleBuilder.setBeanProperty().withName( attributes.getValue( "propertyname" ) );
+
+        int propertyNameFromAttributeIndex = -1;
+        if ( ( propertyNameFromAttributeIndex = attributes.getIndex( "propertynameFromAttribute" ) ) >= 0 )
+        {
+            builder.extractPropertyNameFromAttribute( attributes.getValue( propertyNameFromAttributeIndex ) );
+        }
     }
 
 }
diff --git a/src/main/resources/org/apache/commons/digester3/xmlrules/digester-rules.dtd b/src/main/resources/org/apache/commons/digester3/xmlrules/digester-rules.dtd
index ba1123e..6e43fc2 100644
--- a/src/main/resources/org/apache/commons/digester3/xmlrules/digester-rules.dtd
+++ b/src/main/resources/org/apache/commons/digester3/xmlrules/digester-rules.dtd
@@ -95,8 +95,9 @@
 <!-- Bean Property Setter Rule -->
 <!ELEMENT bean-property-setter-rule EMPTY>
 <!ATTLIST bean-property-setter-rule
-    pattern      CDATA #IMPLIED
-    propertyname CDATA #IMPLIED>
+    pattern                   CDATA #IMPLIED
+    propertyname              CDATA #IMPLIED
+    propertynameFromAttribute CDATA #IMPLIED>
 
 <!-- CallMethodRule
   -
diff --git a/src/site/resources/dtds/digester-rules-3.0.dtd b/src/site/resources/dtds/digester-rules-3.0.dtd
index ba1123e..6e43fc2 100644
--- a/src/site/resources/dtds/digester-rules-3.0.dtd
+++ b/src/site/resources/dtds/digester-rules-3.0.dtd
@@ -95,8 +95,9 @@
 <!-- Bean Property Setter Rule -->
 <!ELEMENT bean-property-setter-rule EMPTY>
 <!ATTLIST bean-property-setter-rule
-    pattern      CDATA #IMPLIED
-    propertyname CDATA #IMPLIED>
+    pattern                   CDATA #IMPLIED
+    propertyname              CDATA #IMPLIED
+    propertynameFromAttribute CDATA #IMPLIED>
 
 <!-- CallMethodRule
   -
diff --git a/src/test/java/org/apache/commons/digester3/BeanPropertySetterRuleTestCase.java b/src/test/java/org/apache/commons/digester3/BeanPropertySetterRuleTestCase.java
index 3584080..d134f47 100644
--- a/src/test/java/org/apache/commons/digester3/BeanPropertySetterRuleTestCase.java
+++ b/src/test/java/org/apache/commons/digester3/BeanPropertySetterRuleTestCase.java
@@ -264,6 +264,29 @@
 
     }
 
+    @Test
+    public void extractPropertyNameFromAttribute() throws Exception
+    {
+        Employee expected = new Employee( "John", "Doe" );
+
+        Employee actual = newLoader( new AbstractRulesModule()
+        {
+
+            @Override
+            protected void configure()
+            {
+                forPattern( "employee" ).createObject().ofType( Employee.class );
+                forPattern( "employee/property" ).setBeanProperty().extractPropertyNameFromAttribute( "name" );
+            }
+
+        } )
+        .newDigester()
+        .parse( getClass().getResource( "extractPropertyNameFromAttribute.xml" ) );
+
+        assertEquals( expected.getFirstName(), actual.getFirstName() );
+        assertEquals( expected.getLastName(), actual.getLastName() );
+    }
+
     /**
      * Get input stream from {@link #TEST_XML}.
      */
diff --git a/src/test/java/org/apache/commons/digester3/xmlrules/BeanPropertySetterRuleTestCase.java b/src/test/java/org/apache/commons/digester3/xmlrules/BeanPropertySetterRuleTestCase.java
new file mode 100644
index 0000000..707a964
--- /dev/null
+++ b/src/test/java/org/apache/commons/digester3/xmlrules/BeanPropertySetterRuleTestCase.java
@@ -0,0 +1,53 @@
+package org.apache.commons.digester3.xmlrules;
+
+import static org.apache.commons.digester3.binder.DigesterLoader.newLoader;
+import static org.junit.Assert.assertEquals;
+
+import org.apache.commons.digester3.Employee;
+import org.junit.Test;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+public final class BeanPropertySetterRuleTestCase
+{
+
+    @Test
+    public void extractPropertyNameFromAttribute() throws Exception
+    {
+        Employee expected = new Employee( "John", "Doe" );
+
+        Employee actual = newLoader( new FromXmlRulesModule()
+        {
+
+            @Override
+            protected void loadRules()
+            {
+                loadXMLRules( getClass().getResource( "extractPropertyNameFromAttribute-rules.xml" ) );
+            }
+
+        } )
+        .newDigester()
+        .parse( getClass().getResource( "../extractPropertyNameFromAttribute.xml" ) );
+
+        assertEquals( expected.getFirstName(), actual.getFirstName() );
+        assertEquals( expected.getLastName(), actual.getLastName() );
+    }
+
+}
diff --git a/src/test/resources/org/apache/commons/digester3/extractPropertyNameFromAttribute.xml b/src/test/resources/org/apache/commons/digester3/extractPropertyNameFromAttribute.xml
new file mode 100644
index 0000000..944008c
--- /dev/null
+++ b/src/test/resources/org/apache/commons/digester3/extractPropertyNameFromAttribute.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+  
+      http://www.apache.org/licenses/LICENSE-2.0
+  
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<employee>
+  <property name="firstName">John</property>
+  <property name="lastName">Doe</property>
+</employee>
diff --git a/src/test/resources/org/apache/commons/digester3/xmlrules/extractPropertyNameFromAttribute-rules.xml b/src/test/resources/org/apache/commons/digester3/xmlrules/extractPropertyNameFromAttribute-rules.xml
new file mode 100644
index 0000000..f5504b9
--- /dev/null
+++ b/src/test/resources/org/apache/commons/digester3/xmlrules/extractPropertyNameFromAttribute-rules.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE digester-rules PUBLIC "-//Apache Commons //DTD digester-rules XML V1.0//EN" "http://commons.apache.org/digester/dtds/digester-rules-3.0.dtd">
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+  
+      http://www.apache.org/licenses/LICENSE-2.0
+  
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<digester-rules>
+  <pattern value="employee">
+    <object-create-rule classname="org.apache.commons.digester3.Employee" />
+    <bean-property-setter-rule pattern="property" propertynameFromAttribute="name" />
+  </pattern>
+</digester-rules>