} else if (localName.equals("data-source")) {
datasource = (DataSource) instantiate(attributes.getValue("class"));
currentobj = datasource;
} else if (localName.equals("column")) {
if (!(datasource instanceof ColumnarDataSource))
throw new DukeConfigException("Column inside data source which " +
"does not support it: " + datasource);
String name = attributes.getValue("name");
if (name == null)
throw new DukeConfigException("Column with no name");
String property = attributes.getValue("property");
String prefix = attributes.getValue("prefix");
String cleanername = attributes.getValue("cleaner");
Cleaner cleaner = makeCleaner(cleanername);
Column c = new Column(name, property, prefix, cleaner);
String spliton = attributes.getValue("split-on");
if (spliton != null)
c.setSplitOn(spliton);
((ColumnarDataSource) datasource).addColumn(c);
} else if (localName.equals("param")) {
String param = attributes.getValue("name");
String value = attributes.getValue("value");
if (currentobj == null)
throw new DukeConfigException("Trying to set parameter " +
param + " but no current object");
// we resolve file references relative to the config file location
if (param.equals("input-file") && path != null &&
!value.startsWith("/"))
value = new File(path, value).getAbsolutePath();
ObjectUtils.setBeanProperty(currentobj, param, value, objects);
} else if (localName.equals("group")) {
groupno++;
// FIXME: now possible to have data sources between the two
// groups. need to check for that, too. ideally XML
// validation should take care of all this for us.
if (groupno == 1 && !config.getDataSources().isEmpty())
throw new DukeConfigException("Cannot have groups in deduplication mode");
else if (groupno == 3)
throw new DukeConfigException("Record linkage mode only supports " +
"two groups");
} else if (localName.equals("object")) {
String klass = attributes.getValue("class");
String name = attributes.getValue("name");