package de.komoot.photon; import com.google.common.base.Joiner; import com.google.common.collect.HashMultimap; import com.google.common.collect.SetMultimap; import com.vividsolutions.jts.geom.Envelope; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import java.io.IOException; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * helper functions to create convert a photon document to XContentBuilder object / JSON * * @author christoph */ public class Utils { private static final Joiner commaJoiner = Joiner.on(", ").skipNulls(); public static XContentBuilder convert(PhotonDoc doc, String[] languages) throws IOException { XContentBuilder builder = XContentFactory.jsonBuilder().startObject() .field(Constants.OSM_ID, doc.getOsmId()) .field(Constants.OSM_TYPE, doc.getOsmType()) .field(Constants.OSM_KEY, doc.getTagKey()) .field(Constants.OSM_VALUE, doc.getTagValue()) .field(Constants.IMPORTANCE, doc.getImportance()); if(doc.getCentroid() != null) { builder.startObject("coordinate") .field("lat", doc.getCentroid().getY()) .field("lon", doc.getCentroid().getX()) .endObject(); } if(doc.getHouseNumber() != null) { builder.field("housenumber", doc.getHouseNumber()); } if(doc.getPostcode() != null) { builder.field("postcode", doc.getPostcode()); } writeName(builder, doc.getName(), languages); writeIntlNames(builder, doc.getCity(), "city", languages); writeIntlNames(builder, doc.getCountry(), "country", languages); writeIntlNames(builder, doc.getState(), "state", languages); writeIntlNames(builder, doc.getStreet(), "street", languages); writeContext(builder, doc.getContext(), languages); writeExtent(builder, doc.getBbox()); return builder; } private static void writeExtent(XContentBuilder builder, Envelope bbox) throws IOException { if(bbox == null) return; if(bbox.getArea() == 0.) return; // http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-geo-shape-type.html#_envelope builder.startObject("extent"); builder.field("type", "envelope"); builder.startArray("coordinates"); builder.startArray().value(bbox.getMinX()).value(bbox.getMaxY()).endArray(); builder.startArray().value(bbox.getMaxX()).value(bbox.getMinY()).endArray(); builder.endArray(); builder.endObject(); } private static void writeName(XContentBuilder builder, Map<String, String> name, String[] languages) throws IOException { Map<String, String> fNames = filterNames(name, languages); if(name.get("alt_name") != null) fNames.put("alt", name.get("alt_name")); if(name.get("int_name") != null) fNames.put("int", name.get("int_name")); if(name.get("loc_name") != null) fNames.put("loc", name.get("loc_name")); if(name.get("old_name") != null) fNames.put("old", name.get("old_name")); if(name.get("reg_name") != null) fNames.put("reg", name.get("reg_name")); write(builder, fNames, "name"); } private static void write(XContentBuilder builder, Map<String, String> fNames, String name) throws IOException { if(fNames.isEmpty()) return; builder.startObject(name); for(Map.Entry<String, String> entry : fNames.entrySet()) { builder.field(entry.getKey(), entry.getValue()); } builder.endObject(); } protected static void writeContext(XContentBuilder builder, Set<Map<String, String>> contexts, String[] languages) throws IOException { final SetMultimap<String, String> multimap = HashMultimap.create(); for(Map<String, String> context : contexts) { if(context.get("name") != null) { multimap.put("default", context.get("name")); } } for(String language : languages) { for(Map<String, String> context : contexts) { if(context.get("name:" + language) != null) { multimap.put(language, context.get("name:" + language)); } } } final Map<String, Collection<String>> map = multimap.asMap(); if(!multimap.isEmpty()) { builder.startObject("context"); for(Map.Entry<String, Collection<String>> entry : map.entrySet()) { builder.field(entry.getKey(), commaJoiner.join(entry.getValue())); } builder.endObject(); } } private static void writeIntlNames(XContentBuilder builder, Map<String, String> names, String name, String[] languages) throws IOException { Map<String, String> fNames = filterNames(names, languages); write(builder, fNames, name); } private static Map<String, String> filterNames(Map<String, String> names, String[] languages) { return filterNames(names, new HashMap<String, String>(), languages); } private static Map<String, String> filterNames(Map<String, String> names, HashMap<String, String> filteredNames, String[] languages) { if(names == null) return filteredNames; if(names.get("name") != null) { filteredNames.put("default", names.get("name")); } for(String language : languages) { if(names.get("name:" + language) != null) { filteredNames.put(language, names.get("name:" + language)); } } return filteredNames; } // http://stackoverflow.com/a/4031040/1437096 public static String stripNonDigits( final CharSequence input /* inspired by seh's comment */) { final StringBuilder sb = new StringBuilder( input.length() /* also inspired by seh's comment */); for(int i = 0; i < input.length(); i++) { final char c = input.charAt(i); if(c > 47 && c < 58) { sb.append(c); } } return sb.toString(); } }