You need to parse XML that contains references to variables, and you need to replace these references with variable values at parse time.
Use Commons Digester’s
MultiVariableExpander
and the
VariableSubstitutor
to expand variable references in an XML document during a parse.
This recipe explores a feature of Commons Digester—variable substitution—which is available only with a prerelease version of Digester, 1.6-dev. To follow the example in this recipe, you must download a nightly snapshot distribution from http://cvs.apache.org/builds/jakarta-commons/nightly/. Use nightly distributions of Commons components at your own risk; these distributions may contain unresolved bugs.
The following XML document contains four variable
references—${email.to}
,
${order.id}
, ${user.name}
,
and ${product.name}—
all of which need to
be replaced with values before the XML is parsed by the
Digester
:
<?xml version="1.0"?> <email to="${email.to}" from="[email protected]"> <subject>Purchase Confirmation: ${order.id}</subject> <priority>High</priority> <message> Dear ${user.name}, we appreciate your business. As CEO of Big Software Company, Inc., I would like to personally thank you for helping us become filthy rich. Your purchase of ${product.name} helped me purchase an even larger boat for myself. Thanks again. </message> </email>
This document represents a purchase confirmation message, and your
system needs to unmarshall the above message to the following class,
Email
:
public class Email { private String to; private String from; private String subject; private String priority; // accessors omitted for brevity. }
The following XML rule set is similar to the rule set defined in
Recipe 6.2. When the parser hits an
email
element, an instance of
Email
is created and properties are populated:
<?xml version="1.0"?> <digester-rules> <pattern value="email"> <object-create-rule classname="com.discursive.jccook.xml.bean.Email"/> <set-next-rule methodname="add" paramtype="java.lang.Object"/> <set-properties-rule/> <bean-property-setter-rule pattern="subject"/> <bean-property-setter-rule pattern="priority"/> <bean-property-setter-rule pattern="message"/> </pattern> </digester-rules>
This difference between this recipe and Recipe 6.2 is that our XML document contains variables to
be replaced at parse time. The following code creates a
Map
that contains variables referenced in the XML
document being parsed. This code creates the variable
Map
, reads the XML rule set from
email-rules.xml
, and parses the XML document
email.xml
:
import org.apache.commons.digester.Digester; import org.apache.commons.digester.Substitutor; import org.apache.commons.digester.substitution.MultiVariableExpander; import org.apache.commons.digester.substitution.VariableSubstitutor; import org.apache.commons.digester.xmlrules.DigesterLoader; // Read the Digester XML rule set and create Digester URL rules = getClass( ).getResource("./email-rules.xml"); Digester digester = DigesterLoader.createDigester(rules); // Create object to push onto Digester Stack List emails = new ArrayList( ); digester.push( emails );// Create Map of variables
Map vars = new HashMap( );
vars.put("email.to", "[email protected]");
vars.put("user.name", "Tim");
vars.put("order.id", "1RR2E223WVVS" );
vars.put("product.name", "Foundation" );
// Create an expander with the Map that matches ${var}
MultiVariableExpander expander = new MultiVariableExpander( );
expander.addSource("$", vars);
// Create a substitutor with the expander
Substitutor substitutor = new VariableSubstitutor(expander);
digester.setSubstitutor(substitutor);
// Parse XML document InputStream input = getClass( ).getResourceAsStream("./email.xml"); digester.parse( input ); // Retrieve Email object Email email = (Email) emails.get(0); System.out.println( "Email Subject: " + email.getSubject( ) ); System.out.println( "Email To: " + email.getTo( ) );
Variable substitution is performed by a
VariableSubstitutor
that has been configured with
a MultiVariableExpander
. The
MultiVariableExpander
retrieves variables from a
Map
, and, in this example, the addSource( )
method is called with a $
marker. This
means that variables are referenced by surrounding a variable name
with ${
and }--${variable}
. The
previous example produces the following output, which demonstrates
the substitution of variables:
Email Subject: Purchase Confirmation: 1RR2E223WVVS Email To: [email protected]
Variable substitution is part parsing, part templating, and can be valuable when you need to specify a set of default properties on a bean that need to be parameterized for different situations. The example in this recipe was an email message confirming a purchase from an e-commerce system, but there are other situations where an object may need to be personalized with a user identifier or a username.
For more information about other new features planned for Digester 1.6, see the current development Javadoc for the Digester at http://jakarta.apache.org/commons/digester/apidocs/index.html.
18.217.147.193