
import java.io.IOException;
import java.io.File;
import java.net.URL;
import java.util.TreeSet;

import org.apache.commons.digester3.Digester;
import org.apache.commons.digester3.ObjectCreateRule;

public class GetMillionCities {
  public static class CityCollection extends TreeSet<City>  {
      public void addCity(City c) {  
        if (c.population > 1000000) this.add(c); System.out.println(c.name);}
  }
  public static void listCities(CityCollection cities) {
      for (City c : cities) { System.out.println(c.name + " " + c.country + " " + c.population); } 
  }
  public static class City implements Comparable{
    String name;
    String country = null;
    int population = -1;
    public void setName(String name) { this.name = name; }
    public void setCountry(String code) { this.country = code; }
    // note: all PCDATA/CDATA values are strings!
    public void makePopulation(String pop) { this.population = new Integer(pop); }
    public int compareTo(Object o) {
         if (this.population < ((City)o).population) return 1; else return -1; }
  }
  public static void main(String[] args) {
    File res = new File("mondial.xml");
    Digester digester = new Digester();
    digester.push(new CityCollection());

    digester.addRule("", new ObjectCreateRule(City.class){
            // at begin() by default pu new City instance on stack,
            // overwrite end() method not to pop stack:
            public void end(String namespace, String name) throws Exception { };
	} );
    // note: reacts only on cities as direct children of countries
    // */city would take all cities,
    // country//city and country/*/city are not allowed;
    digester.addObjectCreate("mondial/country/city", City.class);
    digester.addSetProperties("mondial/country/city", "country", "country");
    digester.addBeanPropertySetter("mondial/country/city/name");
    digester.addCallMethod("mondial/country/city/population", "makePopulation", 1);
    digester.addCallParam("mondial/country/city/population", 0);
    digester.addSetNext("mondial/country/city", "addCity");
    try {
	digester.setValidating(false);
	final CityCollection cities = digester.parse(res);
        System.out.println("####  now listing cities #### ");
        listCities(cities);
	} catch (Exception e) { e.printStackTrace(); } 
  }
}
