/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2003-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.styling;
import java.awt.Color;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.logging.Logger;
import javax.measure.quantity.Length;
import javax.measure.unit.Unit;
import org.geotools.data.DataStore;
import org.geotools.data.FeatureSource;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.feature.FeatureCollection;
import org.geotools.filter.FilterTransformer;
import org.geotools.gml.producer.FeatureTransformer;
import org.geotools.referencing.NamedIdentifier;
import org.geotools.xml.transform.TransformerBase;
import org.geotools.xml.transform.Translator;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.Literal;
import org.opengis.filter.expression.PropertyName;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.style.SemanticType;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
/**
* Produces SLD to an output stream.
*
* @author Ian Schneider
* @source $URL$
*/
public class SLDTransformer extends TransformerBase {
/** The logger for this package. */
private static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geotools.styling");
static final String XLINK_NAMESPACE = "http://www.w3.org/1999/xlink";
static final FilterFactory ff = CommonFactoryFinder.getFilterFactory(null);
/**
* Additional namespace mappings to emit in the start element of the
* generated. Each entry has a URI key and an associated prefix string
* value.
*/
final private Map uri2prefix;
/**
* Construct a new instance of <code>SLDTransformer</code> with the
* default namespace mappings usually found in a simple Styled Layer
* Descriptor element.
*/
public SLDTransformer() {
this(null);
}
/**
* Construct a new instance of <code>SLDTransformer</code> with the
* additional namespace mappings contained in <code>nsBindings</code>.
* <p>
* The designated collection contains mappings of {@link URI} to associated
* prefix (string) to emit in the generated XML element.
*/
public SLDTransformer(Map nsBindings) {
super();
if (nsBindings == null || nsBindings.isEmpty()) {
uri2prefix = new HashMap();
} else {
uri2prefix = new HashMap(nsBindings.size());
int count = 0;
for (Iterator it = nsBindings.entrySet().iterator(); it.hasNext();) {
Map.Entry e = (Entry) it.next();
URI uri = (URI) e.getKey();
String prefix = (String) e.getValue();
if (uri != null && prefix != null) {
uri2prefix.put(uri, prefix.trim());
count++;
}
}
LOGGER.info("Added [" + count
+ "] namespace entries resulting in [" + uri2prefix.size()
+ "] distinct entries");
}
}
public Translator createTranslator(ContentHandler handler) {
Translator result = new SLDTranslator(handler);
// add pre-configured namespace mappings
if (!uri2prefix.isEmpty()) {
for (Iterator it = uri2prefix.entrySet().iterator(); it.hasNext();) {
Map.Entry e = (Entry) it.next();
URI uri = (URI) e.getKey();
if (uri != null) {
String prefix = (String) e.getValue();
// FIXME handle default namespace and possible clash with
// one already known to the namespace-support delegate; i.e.
// the entry with an empty prefix
String uriStr = String.valueOf(uri);
result.getNamespaceSupport().declarePrefix(prefix, uriStr);
}
}
}
return result;
}
/**
* Currently does nothing.
*
* @param args
* DOCUMENT ME!
*
* @throws Exception
* DOCUMENT ME!
*/
public static final void main(String[] args) throws Exception {
java.net.URL url = new java.io.File(args[0]).toURI().toURL();
SLDParser s = new SLDParser( CommonFactoryFinder.getStyleFactory( null), url);
SLDTransformer transformer = new SLDTransformer();
transformer.setIndentation(4);
transformer.transform(s.readXML(),
new FileOutputStream(System.getProperty("java.io.tmpdir")
+ "/junk.eraseme"));
}
/**
* Translates the Style data structure into a series of XML events
* that can be encoded etc...
* <p>
* This Translator makes use of the following (currently hardcoded) information:
* <ul>
* <li>prefix: sld
* <li>namespace: http://www.opengis.net/sld
* </ul>
* @author Jody
*/
static class SLDTranslator extends TranslatorSupport implements StyleVisitor {
/**
* Handles any Filters used in our data structure.
*/
FilterTransformer.FilterTranslator filterTranslator;
/**
* Translates into the default of prefix "sld" for "http://www.opengis.net/sld".
*
* @param handler
*/
public SLDTranslator(ContentHandler handler) {
this( handler, "sld", "http://www.opengis.net/sld");
}
/**
* Translates
* @param handler
*/
public SLDTranslator(ContentHandler handler, String prefix, String uri ) {
super(handler, prefix, uri );
filterTranslator = new FilterTransformer.FilterTranslator(handler);
addNamespaceDeclarations(filterTranslator);
}
boolean isNull( Expression expr ){
if( expr == null ) return true;
if( expr == Expression.NIL ) return true;
if( expr instanceof Literal ){
Literal literal = (Literal) expr;
return literal.getValue() == null;
}
return false; // must be some other non null thing
}
boolean isDefault( Expression expr, Object defaultValue ){
if( defaultValue == null ) return isNull( expr );
if( expr == null ) return false;
if( expr == Expression.NIL ) return false;
if( expr instanceof Literal ){
Literal literal = (Literal) expr;
if( defaultValue.equals( literal.getValue() )){
return true;
}
if( defaultValue.toString().equals( literal.getValue().toString() ) ){
return true;
}
}
return false;
}
/**
* Utility method used to quickly package up the provided expression.
* @param element
* @param expr
*/
void element(String element, Expression expr) {
element(element, expr, null);
}
void element(String element, Expression expr, Object defaultValue) {
if( expr == null || expr == Expression.NIL ) return;
// skip encoding if we are using the default value
if (expr instanceof Literal && defaultValue != null) {
Object value = expr.evaluate(null, defaultValue.getClass());
if(value != null && value.equals(defaultValue)) {
return;
}
}
start(element);
filterTranslator.encode(expr);
end(element);
}
/**
* To be used when the expression is a single literal whose
* value must be written out as element.
* <p>
* For Example OverlapBehaviour is represented as an expression but v 1.0.0
* specifications do not define it as an expression. (<AVERAGE/>)
* </p>
*
*/
void elementLiteral(String element, Expression e, String defaultValue){
if (e == null || e == Expression.NIL) return;
final String value = e.evaluate(null, String.class);
if(defaultValue == null || !defaultValue.equals(value)) {
start(element);
start(value);
end(value);
end(element);
}
}
public void visit(PointPlacement pp) {
start("LabelPlacement");
start("PointPlacement");
pp.getAnchorPoint().accept(this);
visit( pp.getDisplacement() );
element("Rotation", pp.getRotation());
end("PointPlacement");
end("LabelPlacement");
}
public void visit(Stroke stroke) {
start("Stroke");
if (stroke.getGraphicFill() != null) {
start("GraphicFill");
stroke.getGraphicFill().accept(this);
end("GraphicFill");
}
if (stroke.getGraphicStroke() != null) {
start("GraphicStroke");
stroke.getGraphicStroke().accept(this);
end("GraphicStroke");
}
encodeCssParam("stroke", stroke.getColor(), Color.BLACK);
encodeCssParam("stroke-linecap", stroke.getLineCap(), "butt");
encodeCssParam("stroke-linejoin", stroke.getLineJoin(), "miter");
encodeCssParam("stroke-opacity", stroke.getOpacity(), 1.0);
encodeCssParam("stroke-width", stroke.getWidth(), 1.0);
encodeCssParam("stroke-dashoffset", stroke.getDashOffset(), 0.0);
float[] dash = stroke.getDashArray();
if (dash != null) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < dash.length; i++) {
sb.append(dash[i] + " ");
}
encodeCssParam("stroke-dasharray", ff.literal(sb.toString()));
}
end("Stroke");
}
public void visit(LinePlacement lp) {
start("LabelPlacement");
start("LinePlacement");
element("PerpendicularOffset", lp.getPerpendicularOffset());
end("LinePlacement");
end("LabelPlacement");
}
public void visit(AnchorPoint ap) {
start("AnchorPoint");
element("AnchorPointX", ap.getAnchorPointX());
element("AnchorPointY", ap.getAnchorPointY());
end("AnchorPoint");
}
public void visit(TextSymbolizer text) {
if (text == null) {
return;
}
// adds the uom attribute according to the OGC SE specification
AttributesImpl atts = new AttributesImpl();
Unit<Length> uom = text.getUnitOfMeasure();
if(uom != null)
atts.addAttribute("", "uom", "uom", "", UomOgcMapping.get(uom).getSEString());
start("TextSymbolizer", atts);
encodeGeometryExpression(text.getGeometry());
if (text.getLabel() != null) {
element("Label", text.getLabel());
}
if ((text.getFonts() != null) && (text.getFonts().length != 0)) {
start("Font");
Font[] fonts = text.getFonts();
for (int i = 0; i < fonts.length; i++) {
encodeCssParam("font-family", fonts[i].getFontFamily());
}
encodeCssParam("font-size", fonts[0].getFontSize());
encodeCssParam("font-style", fonts[0].getFontStyle());
encodeCssParam("font-weight", fonts[0].getFontWeight());
end("Font");
}
if (text.getPlacement() != null) {
text.getPlacement().accept(this);
}
if (text.getHalo() != null) {
text.getHalo().accept(this);
}
if (text.getFill() != null) {
text.getFill().accept(this);
}
if (text.getOptions() != null) {
encodeVendorOptions(text.getOptions());
}
if (text.getPriority() != null) {
element("Priority", text.getPriority());
}
end("TextSymbolizer");
}
public void visit(RasterSymbolizer raster) {
if (raster == null) {
return;
}
// adds the uom attribute according to the OGC SE specification
AttributesImpl atts = new AttributesImpl();
Unit<Length> uom = raster.getUnitOfMeasure();
if(uom != null)
atts.addAttribute("", "uom", "uom", "", UomOgcMapping.get(uom).getSEString());
start("RasterSymbolizer", atts);
encodeGeometryExpression(raster.getGeometry());
element("Opacity", raster.getOpacity(), 1.0);
if (raster.getChannelSelection() != null) {
final ChannelSelection cs = raster.getChannelSelection();
if (cs.getGrayChannel() != null) {
start("ChannelSelection");
SelectedChannelType gray = cs.getGrayChannel();
start("GrayChannel");
gray.accept(this);
end("GrayChannel");
end("ChannelSelection");
} else if( cs.getRGBChannels() != null && cs.getRGBChannels().length ==3 && cs.getRGBChannels()[0] != null && cs.getRGBChannels()[1] != null && cs.getRGBChannels()[2] != null){
start("ChannelSelection");
SelectedChannelType[] rgb = cs.getRGBChannels();
start("RedChannel");
rgb[0].accept(this);
end("RedChannel");
start("GreenChannel");
rgb[1].accept(this);
end("GreenChannel");
start("BlueChannel");
rgb[2].accept(this);
end("BlueChannel");
end("ChannelSelection");
}
else {
// we have an invalid ChannelSelection ?
}
}
if (raster.getOverlap() != null) {
Expression overlaps = raster.getOverlap();
if( overlaps instanceof PropertyName){
final String pn = ((PropertyName)overlaps).getPropertyName();
if("RANDOM".equals(pn)) {
start("OverlapBehavior");
start(pn);
end(pn);
end("OverlapBehavior");
}
} else {
//this expression needs to be converted to a single string and then written
//1.0.0 specs don't allow it to be written as an expression
elementLiteral("OverlapBehavior",overlaps, "RANDOM");
}
}
ColorMap colorMap = raster.getColorMap();
if (colorMap != null && colorMap.getColorMapEntries() != null && colorMap.getColorMapEntries().length > 0) {
colorMap.accept(this);
}
if (raster.getContrastEnhancement() != null){
raster.getContrastEnhancement().accept(this);
}
if (raster.getShadedRelief() != null) {
raster.getShadedRelief().accept(this);
}
if (raster.getImageOutline() != null) {
start("ImageOutline");
raster.getImageOutline().accept(this);
end("ImageOutline");
}
end("RasterSymbolizer");
}
public void visit(ColorMap colorMap) {
// The type of the ColorMap is stored in an attribute "type" and may store
// string-values: "ramp", "intervals" or "values".
AttributesImpl atts = new AttributesImpl();
String typeString;
if (colorMap.getType() == ColorMap.TYPE_INTERVALS)
typeString = "intervals";
else if (colorMap.getType() == ColorMap.TYPE_VALUES)
typeString = "values";
else
typeString = "ramp"; // Also the default in the parser
if(!"ramp".equals(typeString)) {
atts.addAttribute("", "type", "type", "", typeString);
}
start("ColorMap", atts);
ColorMapEntry[] mapEntries = colorMap.getColorMapEntries();
for (int i = 0; i < mapEntries.length; i++) {
mapEntries[i].accept(this);
}
end("ColorMap");
}
public void visit(ColorMapEntry colorEntry) {
if (colorEntry != null) {
AttributesImpl atts = new AttributesImpl();
atts.addAttribute("", "color", "color", "", colorEntry.getColor().toString());
if (colorEntry.getOpacity() != null) {
atts.addAttribute("", "opacity", "opacity", "", colorEntry.getOpacity().toString());
}
if (colorEntry.getQuantity() != null) {
atts.addAttribute("", "quantity", "quantity", "", colorEntry.getQuantity().toString());
}
if (colorEntry.getLabel() != null) {
atts.addAttribute("", "label", "label", "", colorEntry.getLabel());
}
element("ColorMapEntry", (String) null, atts);
}
}
public void visit(Symbolizer sym) {
try {
contentHandler.startElement("", "!--", "!--", NULL_ATTS);
chars("Unidentified Symbolizer " + sym.getClass());
contentHandler.endElement("", "--", "--");
} catch (SAXException se) {
throw new RuntimeException(se);
}
}
public void visit(PolygonSymbolizer poly) {
// adds the uom attribute according to the OGC SE specification
AttributesImpl atts = new AttributesImpl();
Unit<Length> uom = poly.getUnitOfMeasure();
if(uom != null)
atts.addAttribute("", "uom", "uom", "", UomOgcMapping.get(uom).getSEString());
start("PolygonSymbolizer", atts);
encodeGeometryExpression(poly.getGeometry());
if (poly.getFill() != null) {
poly.getFill().accept(this);
}
if (poly.getStroke() != null) {
poly.getStroke().accept(this);
}
end("PolygonSymbolizer");
}
public void visit(ExternalGraphic exgr) {
start("ExternalGraphic");
AttributesImpl atts = new AttributesImpl();
try {
atts.addAttribute(XMLNS_NAMESPACE, "xlink", "xmlns:xlink", "", XLINK_NAMESPACE);
atts.addAttribute(XLINK_NAMESPACE, "type", "xlink:type", "", "simple");
atts.addAttribute(XLINK_NAMESPACE, "xlink", "xlink:href","", exgr.getLocation().toString());
} catch (java.net.MalformedURLException murle) {
throw new Error("SOMEONE CODED THE X LINK NAMESPACE WRONG!!");
}
element("OnlineResource", (String) null, atts);
element("Format", exgr.getFormat());
end("ExternalGraphic");
}
public void visit(LineSymbolizer line) {
// adds the uom attribute according to the OGC SE specification
AttributesImpl atts = new AttributesImpl();
Unit<Length> uom = line.getUnitOfMeasure();
if(uom != null)
atts.addAttribute("", "uom", "uom", "", UomOgcMapping.get(uom).getSEString());
start("LineSymbolizer", atts);
encodeGeometryExpression(line.getGeometry());
if( line.getStroke() != null ){
line.getStroke().accept(this);
}
end("LineSymbolizer");
}
public void visit(Fill fill) {
start("Fill");
if (fill.getGraphicFill() != null) {
start("GraphicFill");
fill.getGraphicFill().accept(this);
end("GraphicFill");
}
encodeCssParam("fill", fill.getColor(), "#808080");
encodeCssParam("fill-opacity", fill.getOpacity(), 1.0);
end("Fill");
}
public void visit(Rule rule) {
start("Rule");
if (rule.getName() != null) element("Name", rule.getName());
if (rule.getTitle() != null) element("Title", rule.getTitle());
if (rule.getAbstract() != null) element("Abstract", rule.getAbstract());
Graphic[] gr = rule.getLegendGraphic();
for (int i = 0; i < gr.length; i++) {
start("LegendGraphic");
gr[i].accept(this);
end("LegendGraphic");
}
Filter filter = rule.getFilter();
if( filter == null || filter == Filter.INCLUDE ){
// no filter
}
else {
try {
contentHandler.startElement("", "", "ogc:Filter", NULL_ATTS);
filterTranslator.encode(filter);
contentHandler.endElement("","","ogc:Filter");
} catch (SAXException se) {
throw new RuntimeException(se);
}
}
if (rule.isElseFilter()) {
start("ElseFilter");
end("ElseFilter");
}
if (rule.getMinScaleDenominator() != 0.0) {
element("MinScaleDenominator",
rule.getMinScaleDenominator() + "");
}
if (rule.getMaxScaleDenominator() != Double.POSITIVE_INFINITY) {
element("MaxScaleDenominator",
rule.getMaxScaleDenominator() + "");
}
Symbolizer[] sym = rule.getSymbolizers();
for (int i = 0; i < sym.length; i++) {
sym[i].accept(this);
}
end("Rule");
}
public void visit(Mark mark) {
start("Mark");
if (mark.getWellKnownName() != null && !"square".equals(mark.getWellKnownName().evaluate(null))) {
element("WellKnownName", mark.getWellKnownName().toString());
}
if (mark.getFill() != null) {
mark.getFill().accept(this);
}
if (mark.getStroke() != null) {
mark.getStroke().accept(this);
}
end("Mark");
}
public void visit(PointSymbolizer ps) {
// adds the uom attribute according to the OGC SE specification
AttributesImpl atts = new AttributesImpl();
Unit<Length> uom = ps.getUnitOfMeasure();
if(uom != null)
atts.addAttribute("", "uom", "uom", "", UomOgcMapping.get(uom).getSEString());
start("PointSymbolizer", atts);
encodeGeometryExpression(ps.getGeometry());
ps.getGraphic().accept(this);
end("PointSymbolizer");
}
public void visit(Halo halo) {
start("Halo");
if (halo.getRadius() != null) {
start("Radius");
filterTranslator.encode(halo.getRadius());
end("Radius");
}
if (halo.getFill() != null) {
halo.getFill().accept(this);
}
end("Halo");
}
public void visit(Graphic gr) {
start("Graphic");
encodeGeometryProperty(gr.getGeometryPropertyName());
Symbol[] symbols = gr.getSymbols();
for (int i = 0; i < symbols.length; i++) {
symbols[i].accept(this);
}
element("Opacity", gr.getOpacity(), 1.0);
element("Size", gr.getSize());
element("Rotation", gr.getRotation(), 0.0);
visit(gr.getDisplacement());
end("Graphic");
}
public void visit(StyledLayerDescriptor sld) {
AttributesImpl atts = new AttributesImpl();
atts.addAttribute("", "version", "version", "", "1.0.0");
start("StyledLayerDescriptor", atts);
if ((sld.getName() != null) && (sld.getName().length() > 0)) {
element("Name", sld.getName()); //optional
}
if ((sld.getTitle() != null) && (sld.getTitle().length() > 0)) {
element("Title", sld.getTitle()); //optional
}
if ((sld.getAbstract() != null) && (sld.getAbstract().length() > 0)) {
element("Abstract", sld.getAbstract()); //optional
}
StyledLayer[] layers = sld.getStyledLayers();
for (int i = 0; i < layers.length; i++) {
if (layers[i] instanceof NamedLayer) {
visit((NamedLayer) layers[i]);
} else if (layers[i] instanceof UserLayer) {
visit((UserLayer) layers[i]);
} else {
throw new IllegalArgumentException("StyledLayer '"
+ layers[i].getClass().toString() + "' not found");
}
}
end("StyledLayerDescriptor");
}
public void visit(NamedLayer layer) {
start("NamedLayer");
element("Name", layer.getName());
FeatureTypeConstraint[] lfc = layer.getLayerFeatureConstraints();
if ((lfc != null) && lfc.length > 0) {
start("LayerFeatureConstraints"); //optional
for (int i = 0; i < lfc.length; i++) {
visit(lfc[i]);
}
end("LayerFeatureConstraints");
}
Style[] styles = layer.getStyles();
for (int i = 0; i < styles.length; i++) {
visit(styles[i]);
}
end("NamedLayer");
}
public void visit(UserLayer layer) {
start("UserLayer");
if ((layer.getName() != null) && (layer.getName().length() > 0)) {
element("Name", layer.getName()); //optional
}
DataStore inlineFDS = layer.getInlineFeatureDatastore();
if (inlineFDS != null) {
visitInlineFeatureType(inlineFDS, layer.getInlineFeatureType());
} else if (layer.getRemoteOWS() != null) {
visit(layer.getRemoteOWS());
}
start("LayerFeatureConstraints"); //required
FeatureTypeConstraint[] lfc = layer.getLayerFeatureConstraints();
if ((lfc != null) && lfc.length > 0) {
for (int i = 0; i < lfc.length; i++) {
visit(lfc[i]);
}
} else { //create an empty FeatureTypeConstraint, since it is required
start("FeatureTypeConstraint");
end("FeatureTypeConstraint");
}
end("LayerFeatureConstraints");
Style[] styles = layer.getUserStyles();
for (int i = 0; i < styles.length; i++) {
visit(styles[i]);
}
end("UserLayer");
}
private void visitInlineFeatureType(DataStore dataStore,
SimpleFeatureType featureType) {
start("InlineFeature");
try {
final String ftName = featureType.getTypeName();
final FeatureSource<SimpleFeatureType, SimpleFeature> fs = dataStore.getFeatureSource(ftName);
final FeatureCollection<SimpleFeatureType, SimpleFeature> fc = fs.getFeatures();
final FeatureTransformer ftrax = new FeatureTransformer();
ftrax.setCollectionNamespace(null);
ftrax.setCollectionPrefix(null);
ftrax.setGmlPrefixing(true);
ftrax.setIndentation(2);
final CoordinateReferenceSystem crs = featureType
.getGeometryDescriptor().getCoordinateReferenceSystem();
String srsName = null;
if (crs == null) {
LOGGER.warning("Null CRS in feature type named [" + ftName
+ "]. Ignore CRS");
} else {
// assume the first named identifier of this CRS is its
// fully
// qualified code; e.g. authoriy and SRID
Set ids = crs.getIdentifiers();
if (ids == null || ids.isEmpty()) {
LOGGER.warning("Null or empty set of named identifiers "
+ "in CRS ["
+ crs
+ "] of feature type named ["
+ ftName
+ "]. Ignore CRS");
} else {
for (Iterator it = ids.iterator(); it.hasNext();) {
NamedIdentifier id = (NamedIdentifier) ids
.iterator().next();
if (id != null) {
srsName = String.valueOf(id);
break;
}
}
}
}
if (srsName != null) {
// Some Server implementations using older versions of this
// library barf on a fully qualified CRS name with messages
// like : "couldnt decode SRS - EPSG:EPSG:4326. currently
// only supporting EPSG #"; looks like they only needs the
// SRID. adjust
final int ndx = srsName.indexOf(':');
if (ndx > 0) {
LOGGER.info("Reducing CRS name [" + srsName
+ "] to its SRID");
srsName = srsName.substring(ndx + 1).trim();
}
ftrax.setSrsName(srsName);
}
final String defaultNS = this.getDefaultNamespace();
ftrax.getFeatureTypeNamespaces().declareDefaultNamespace("",
defaultNS);
final String ns = featureType.getName().getNamespaceURI();
if (ns == null) {
LOGGER.info("Null namespace URI in feature type named ["
+ ftName + "]. Ignore namespace in features");
} else {
// find the URI's prefix mapping in this namespace support
// delegate and use it; otherwise ignore it
final String prefix = this.nsSupport.getPrefix(ns);
if (prefix != null)
ftrax.getFeatureTypeNamespaces().declareNamespace(
featureType, prefix, ns);
}
final Translator t = ftrax
.createTranslator(this.contentHandler);
t.encode(fc);
} catch (IOException ignored) {
}
end("InlineFeature");
}
public void visit(RemoteOWS remoteOWS) {
start("RemoteOWS");
element("Service", remoteOWS.getService());
element("OnlineResource", remoteOWS.getOnlineResource());
end("RemoteOWS");
}
public void visit(FeatureTypeConstraint ftc) {
start("FeatureTypeConstraint");
if (ftc != null) {
element("FeatureTypeName", ftc.getFeatureTypeName());
visit(ftc.getFilter());
Extent[] extent = ftc.getExtents();
for (int i = 0; i < extent.length; i++) {
visit(extent[i]);
}
}
end("FeatureTypeConstraint");
}
public void visit(Extent extent) {
start("Extent");
element("Name", extent.getName());
element("Value", extent.getValue());
end("Extent");
}
public void visit(Filter filter) {
// TODO: implement this visitor
}
public void visit(Style style) {
if (style instanceof NamedStyle) {
start("NamedStyle");
element("Name", style.getName());
end("NamedStyle");
} else {
start("UserStyle");
element("Name", style.getName());
element("Title", style.getTitle());
if(style.isDefault()) {
element("IsDefault", "1");
}
elementSafe("Abstract", style.getAbstract());
FeatureTypeStyle[] fts = style.getFeatureTypeStyles();
for (int i = 0; i < fts.length; i++) {
visit(fts[i]);
}
end("UserStyle");
}
}
public void visit(FeatureTypeStyle fts) {
start("FeatureTypeStyle");
if ((fts.getName() != null) && (fts.getName().length() > 0)) {
element("Name", fts.getName());
}
if ((fts.getTitle() != null) && (fts.getTitle().length() > 0)) {
element("Title", fts.getTitle());
}
if ((fts.getAbstract() != null) && (fts.getAbstract().length() > 0)) {
element("Abstract", fts.getAbstract());
}
if ((fts.featureTypeNames() != null) && (fts.featureTypeNames().size() > 0)) {
element("FeatureTypeName", fts.featureTypeNames().iterator().next().toString());
}
String[] sti = fts.getSemanticTypeIdentifiers();
if(sti.length == 1 && sti[0].equals(SemanticType.ANY.toString())) {
// skip, it's the default
} else {
for (int i = 0; i < sti.length; i++) {
element("SemanticTypeIdentifier", sti[i]);
}
}
Rule[] rules = fts.getRules();
for (int i = 0; i < rules.length; i++) {
rules[i].accept(this);
}
end("FeatureTypeStyle");
}
public void visit(Displacement dis) {
if (dis == null){
return;
}
// We don't want to get huge SLDs with default values. So if displacement = 0 and 0 we
// drop it.
Expression dx = dis.getDisplacementX();
Expression dy = dis.getDisplacementY();
if( isNull(dx) && isNull(dy)){
return;
}
if( isDefault(dx,0) && isDefault(dy,0)){
return;
}
start("Displacement");
element("DisplacementX", dis.getDisplacementX());
element("DisplacementY", dis.getDisplacementY());
end("Displacement");
}
void encodeGeometryProperty(String name) {
if ((name == null) || (name.trim().length() == 0)) {
return;
}
//create a property name out the name and encode it
FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null);
Expression expression = ff.property(name);
start("Geometry");
filterTranslator.encode(expression);
end("Geometry");
}
void encodeGeometryExpression(Expression geom) {
if ((geom == null)) {
return;
}
start("Geometry");
filterTranslator.encode(geom);
end("Geometry");
}
void encodeCssParam(String name, Expression expression) {
encodeCssParam(name, expression, null);
}
void encodeCssParam(String name, Expression expression, Object defaultValue) {
if (expression == null) {
return; // protect ourselves from things like a null Stroke Color
}
// skip encoding if we are using the default value
if (expression instanceof Literal && defaultValue != null) {
Object value = expression.evaluate(null, defaultValue.getClass());
if(value != null && value.equals(defaultValue)) {
return;
}
}
AttributesImpl atts = new AttributesImpl();
atts.addAttribute("", "name", "name", "", name);
if(expression instanceof Literal) {
// use more compact encoding
element("CssParameter", expression.evaluate(null, String.class), atts);
} else {
start("CssParameter", atts);
filterTranslator.encode(expression);
end("CssParameter");
}
}
void encodeVendorOptions(Map options) {
if (options != null) {
Iterator it = options.keySet().iterator();
while (it.hasNext()) {
String key = (String) it.next();
String value = (String) options.get(key);
encodeVendorOption(key, value);
}
}
}
void encodeVendorOption(String key, String value) {
AttributesImpl atts = new AttributesImpl();
atts.addAttribute("", "name", "name", "", key);
start("VendorOption", atts);
chars(value);
end("VendorOption");
}
public void encode(Style[] styles) {
try {
contentHandler.startDocument();
start("StyledLayerDescriptor", NULL_ATTS);
start("NamedLayer", NULL_ATTS); //this is correct?
for (int i = 0, ii = styles.length; i < ii; i++) {
styles[i].accept(this);
}
end("NamedLayer");
end("StyledLayerDescriptor");
contentHandler.endDocument();
} catch (SAXException se) {
throw new RuntimeException(se);
}
}
public void encode(StyledLayerDescriptor sld) {
try {
contentHandler.startDocument();
sld.accept(this);
contentHandler.endDocument();
} catch (SAXException se) {
throw new RuntimeException(se);
}
}
public void encode(Object o) throws IllegalArgumentException {
if (o instanceof StyledLayerDescriptor) {
encode((StyledLayerDescriptor) o);
} else if (o instanceof Style[]) {
encode((Style[]) o);
} else {
Class c = o.getClass();
try {
java.lang.reflect.Method m = c.getMethod("accept",
new Class[] { StyleVisitor.class });
m.invoke(o, new Object[] { this });
} catch (NoSuchMethodException nsme) {
throw new IllegalArgumentException("Cannot encode " + o);
} catch (Exception e) {
throw new RuntimeException(
"Internal transformation exception", e);
}
}
}
public void visit(ContrastEnhancement ce) {
if (ce == null || ce.getMethod() == null)
return;
start("ContrastEnhancement");
// histogram
Literal exp = (Literal) ce.getType();
if (exp != null) {
final String val = (String) exp.getValue();
start(val);
end(val);
}
//gamma
exp=(Literal)ce.getGammaValue();
if (exp != null) {
//gamma is a double so the actual value needs to be printed here
element("GammaValue", ((Literal)exp).getValue().toString());
// element("GammaValue", exp);
}
end("ContrastEnhancement");
}
public void visit(ImageOutline outline) {
if(outline==null)
return;
start("ImageOutline");
outline.getSymbolizer().accept(this);
end("ImageOutline");
}
public void visit(ChannelSelection cs) {
if(cs==null)
return;
start("ChannelSelection");
final SelectedChannelType[] sct = cs.getSelectedChannels();
for (int i = 0; i < sct.length && sct != null; i++)
visit(sct[i]);
end("ChannelSelection");
}
public void visit(OverlapBehavior ob) {
start("OverlapBehavior");
final String pn = (String) ob.getValue();
start(pn);
end(pn);
end("OverlapBehavior");
}
public void visit(SelectedChannelType sct) {
element("SourceChannelName", sct.getChannelName());
final ContrastEnhancement ce = sct.getContrastEnhancement();
if (ce != null)
ce.accept(this);
}
public void visit(ShadedRelief sr) {
start("ShadedRelief");
//brightnessonly
if(sr.isBrightnessOnly())
element("BrightnessOnly", "true");
else
element("BrightnessOnly", "false");
//relief factor
if(sr.getReliefFactor()!=null)
{
// element("ReliefFactor",sr.getReliefFactor());
//this expression needs to be converted to a single string and then written
//1.0.0 specs don't allow it to be written as an expression
Literal l = (Literal)sr.getReliefFactor();
element("ReliefFactor", l.getValue().toString());
}
end("ShadedRelief");
}
}
}